//
//  CouchBaseLiteLib.m
//  FMS
//
//  Created by Steven on 10/19/13.
//  Copyright (c) 2013 QGSVN. All rights reserved.
//

#import "CouchBaseLiteLib.h"
#import "ListServerVCNew.h"
#import "LiaisonBaseLite.h"

NSString* const SyncManagerStateChangedNotification = @"SyncManagerStateChanged";

@implementation CouchBaseLiteLib
@synthesize database = _database;

+ (CouchBaseLiteLib *)sharedCouchBaseLite
{
    static CouchBaseLiteLib *_sharedClient = nil;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedClient = [[CouchBaseLiteLib alloc] init];
    });
    
    return _sharedClient;
}
- (CouchBaseLiteLib *)init{
    self = [super init];
    if (self) {
        // Get or create the database.
        NSError* error;
        _database = [[CBLManager sharedInstance] createDatabaseNamed: kDatabaseName
                                                               error: &error];
        _replications = [[NSMutableArray alloc] init];
        [self addReplications: _database.allReplications];
    }
    return self;
}


#pragma mark - SYNC:


// Gets the current replication URL.
- (void) addReplication: (CBLReplication*)repl {
    if (![_replications containsObject: repl]) {
        [_replications addObject: repl];
        if (!_syncURL)
            _syncURL = repl.remoteURL;
        if (repl.continuous)
            _continuous = true;
        [[NSNotificationCenter defaultCenter] addObserver: self
                                                 selector: @selector(replicatorChanged:)
                                                     name: kCBLReplicationChangeNotification
                                                   object: repl];
    }
}


- (void) addReplications: (NSArray*)replications {
    for (CBLReplication* repl in replications) {
        [self addReplication: repl];
    }
}


- (void) forgetReplication: (CBLReplication*)repl {
    [_replications removeObject: repl];
    [[NSNotificationCenter defaultCenter] removeObserver: self
                                                    name: kCBLReplicationChangeNotification
                                                  object: repl];
}


- (void) forgetAll {
    for (CBLReplication* repl in [_replications mutableCopy]) {
        [self forgetReplication:repl];
    }
    if (_replications != nil)
        _replications = nil;
    _replications = [[NSMutableArray alloc] init];
    _syncURL = nil;
}


- (void) setSyncURL: (NSURL*)url {
    if (url == _syncURL || [url isEqual: _syncURL])
        return;
    [self forgetAll];
    if (url) {
        NSArray *repls = [_database replicateWithURL: url exclusively: YES];
        for (CBLReplication* repl in repls) {
            repl.persistent = YES;
            repl.continuous = _continuous;
            if (repl.pull) {
                double timeDuration = [[[NSUserDefaults standardUserDefaults] objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
                
                NSString *startDate = [NSString stringWithFormat:@"%.0lf",[[[NSDate date] dateByAddingTimeInterval:-timeDuration] timeIntervalSince1970]];
//                NSString *endDate = [NSString stringWithFormat:@"%.0lf",[[NSDate date] timeIntervalSince1970]];
                
                //return data from startDate
                NSString *paramDuration = [NSString stringWithFormat:@"%@,99999999999",startDate];
                
                if (timeDuration > [[NSDate date] timeIntervalSince1970])
                    paramDuration = [NSString stringWithFormat:@"0,99999999999"];
                NSLog(@"paramDuration - %@",paramDuration);

                [repl setQuery_params:[NSDictionary dictionaryWithObjectsAndKeys:paramDuration,@"arrayFilter", nil]];
                [repl setFilter:@"synchDB/syncDatabaseFMS"];
//                repl.filter = @"synchDB/syncFMS";
            }
            [self addReplication: repl];
        }
    }
}

- (void) setContinuous:(bool)continuous {
    _continuous = continuous;
    for (CBLReplication* repl in _replications)
        repl.continuous = continuous;
}

- (void) syncNow {
    
//    for (CBLReplication* repl in _replications) {
//        if (repl.pull) {
//            long timeDuration = [[[NSUserDefaults standardUserDefaults] objectForKey:TIME_DURATION_DB_SERVER] longValue];
//            
//            NSString *startDate = [NSString stringWithFormat:@"%.0lf",[[[NSDate date] dateByAddingTimeInterval:-timeDuration] timeIntervalSince1970]];
//            NSString *endDate = [NSString stringWithFormat:@"%.0lf",[[NSDate date] timeIntervalSince1970]];
//            NSString *paramDuration = [NSString stringWithFormat:@"%@;%@",startDate,endDate];
//            
//            NSLog(@"paramDuration - %@",paramDuration);
//            
//            repl.query_params = [[NSDictionary alloc] initWithObjectsAndKeys:paramDuration, @"arrayFilter", nil];
//            repl.filter = @"synchDB/syncDatabaseFMS";
//        }
//        if (!repl.continuous)
//            [repl start];
//    }
//    int isFistSync = [[[NSUserDefaults standardUserDefaults] objectForKey:@"isFirstSync"] intValue];
//    BOOL isLogin = [[[NSUserDefaults standardUserDefaults] objectForKey:@"isLogin"] boolValue];
//    if ((isFistSync) && isLogin) {
//        [[NSNotificationCenter defaultCenter] postNotificationName:kLoginSuccessSynNow object:nil];
//    }
    
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    NSURL *url  = [NSURL URLWithString:[userDefaults objectForKey:@"syncpoint"]];
    
    [self forgetAll];
    if (url) {
        NSArray *repls = [_database replicateWithURL: url exclusively: YES];
        for (CBLReplication* repl in repls) {
            
            repl.persistent = YES;
            repl.continuous = _continuous;
            if (repl.pull)
                repl.filter = nil;

            [self addReplication: repl];
        }
    }
}

- (void) setRemoteDatebaseUrl:(NSString*)_remoteDBUrl authenticateUser:(NSDictionary*)dict {
    NSLog(@"_remoteDBUrl=%@",_remoteDBUrl);
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    NSString *currentRemoteDBUrl = [userDefaults objectForKey:CURRENT_REMOTE_DATABASE_URL];
    if (_remoteDBUrl != nil && ![_remoteDBUrl isEqualToString:currentRemoteDBUrl]) {
        
        [userDefaults setObject:_remoteDBUrl forKey:CURRENT_REMOTE_DATABASE_URL];
        
        NSString *username = [dict objectForKey:@"username"];
        if ([username isEqualToString:@""] || username == nil)
            ;
        else
        {
            [userDefaults setObject:[dict objectForKey:@"username"] forKey:CURRENT_USER_NAME_URL];
            [userDefaults setObject:[dict objectForKey:@"password"] forKey:CURRENT_USER_PASS_URL];
            if ([_remoteDBUrl rangeOfString:@"https"].location != NSNotFound) {
                _remoteDBUrl = [NSString stringWithFormat:@"http://%@:%@@%@",[dict objectForKey:@"username"],[dict objectForKey:@"password"],[_remoteDBUrl substringFromIndex:8]];
            }
            else
                _remoteDBUrl = [NSString stringWithFormat:@"http://%@:%@@%@",[dict objectForKey:@"username"],[dict objectForKey:@"password"],[_remoteDBUrl substringFromIndex:7]];
        }
        
        [userDefaults setObject:_remoteDBUrl forKey:@"syncpoint"];
        [userDefaults synchronize];
        [self setContinuous:YES];
        [self setSyncURL:[NSURL URLWithString:_remoteDBUrl]];
    }
    else {
        if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"isLogin"] boolValue]) {
            [[NSNotificationCenter defaultCenter] postNotificationName:kLoginSuccessSynNow object:nil];
        }
    }
}

// Called when a replication's state changes
- (void) replicatorChanged: (NSNotificationCenter*)n {
    // First collect the aggregate state of both (pull+push) replications:
    BOOL active = NO;
    unsigned completed = 0, total = 0;
    NSError* error = nil;
    CBLReplicationMode mode = kCBLReplicationStopped;
    for (CBLReplication* repl in _replications) {
        mode = MAX(mode, repl.mode);
        if (!error)
            error = repl.error;
        if (repl.mode == kCBLReplicationActive) {
            completed += repl.completed;
            total += repl.total;
            active = YES;
        }
    }
    
    if (error != _error && error.code == 401) {
        // Auth needed (or auth is incorrect). See if the delegate wants to do its own auth;
        // otherwise put up a username/password login panel:
    
    }
    
    // Now update the UI:
    if (active != _active || completed != _completed || total != _total || mode != _mode
        || error != _error) {
        _active = active;
        _completed = completed;
        _total = total;
        _progress = (completed / (float)MAX(total, 1u));
        _mode = mode;
        _error = error;
        NSLog(@"SYNCMGR: active=%d; mode=%d; %u/%u; %@",
              active, mode, completed, total, error.localizedDescription); //FIX: temporary logging
        //infor sync change
        NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:completed],@"completed",[NSNumber numberWithInt:total],@"total",[NSNumber numberWithBool:active],@"active", nil];
        [[NSNotificationCenter defaultCenter]
         postNotificationName: SyncManagerStateChangedNotification
         object:dict];
        
        if (mode == kCBLReplicationIdle) {
//            [ApplicationDelegate setProgressBarHidden:YES];
//            [ApplicationDelegate setProgressBar:0];
            [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:0] forKey:CURRENT_PROGRESS_VALUE];
            //hide activity view
            [ApplicationDelegate.myIndicatorView stopAnimating];
            
//            NSNumber *isFirstSync = [[NSUserDefaults standardUserDefaults] objectForKey:@"isFirstSync"];
//            if ([isFirstSync intValue] == 0) {
//                [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:1] forKey:@"isFirstSync"];
            
//                [[NSUserDefaults standardUserDefaults] synchronize];
            
//                if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"isLogin"] boolValue]) {
//                    [[NSNotificationCenter defaultCenter] postNotificationName:kLoginSuccessSynNow object:nil];
//                }
//            }
            if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"isLogin"] boolValue]) {
                [[NSNotificationCenter defaultCenter] postNotificationName:kLoginSuccessSynNow object:nil];
            }
        }
        else {
//            float progressValue = (float)completed/total;
//            
//            float previousProgressValue = [[[NSUserDefaults standardUserDefaults] objectForKey:CURRENT_PROGRESS_VALUE] floatValue];
//            
//            if (previousProgressValue < progressValue) {
//                [ApplicationDelegate setProgressBar:progressValue];
//                [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:progressValue] forKey:CURRENT_PROGRESS_VALUE];
//            }
            //hide activity view
            [ApplicationDelegate.myIndicatorView startAnimating];
        }
    }
}

//set username and password
- (void) setUsername: (NSString*)username password: (NSString*)password {

    NSURLCredential* cred = [NSURLCredential credentialWithUser: username
                                                       password: password
                                                    persistence: NSURLCredentialPersistencePermanent];
    for (CBLReplication* repl in _replications) {
        repl.credential = cred;
    }
}

- (void) recreateLocalDatabase {
    /********************* Create CBLDB *********************/
    NSLog(@"Creating database...");
    NSError *error;
    _database = [[CBLManager sharedInstance] createDatabaseNamed: kDatabaseName
                                                           error: &error];
    if (_replications == nil)
        _replications = [[NSMutableArray alloc] init];
    [self addReplications: _database.allReplications];
    
    if (error) {
        NSLog(@"Can not create database error %@",error);
    }
    
}

- (void) deleteLocalDatabaseWithParent:(id)_parent{
    NSError *error;
    [_database deleteDatabase:&error];
    if (error) {
        NSLog(@"Can not delete database error %@",error);
    }
    else
    {
        NSLog(@"Delete local db");
        if (_parent) {
            UIAlertView *dialog = [[UIAlertView alloc] initWithTitle:nil message:@"The local database is clear successfully." delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK" , nil];
            [dialog show];
        }
        NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
        [userDefaults setObject:[NSNumber numberWithInt:0] forKey:@"isFirstSync"];
        [userDefaults setObject:@"" forKey:CURRENT_REMOTE_DATABASE_URL];
        [userDefaults setObject:@"" forKey:CURRENT_USER_NAME_URL];
        [userDefaults setObject:@"" forKey:CURRENT_USER_PASS_URL];
        [userDefaults setObject:@"" forKey:@"syncpoint"];
        [userDefaults setObject:[NSNumber numberWithFloat:0] forKey:CURRENT_PROGRESS_VALUE];
        
        if ([_parent respondsToSelector:@selector(reloadSynDataBase)]) {
            [_parent reloadSynDataBase];
        }

        [self forgetAll];
        [self removeDatabaseCache];
        [self recreateLocalDatabase];
    }
}

- (void) removeDatabaseCache {
    //remove all cache folder
    NSString *documentdir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
    NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentdir error:nil];
    NSString *item;
    for (item in directoryContent){
        NSString *filePath = [documentdir stringByAppendingPathComponent:item];
        filePath = [filePath stringByAppendingPathComponent:@"CouchbaseLite"];
        if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
            NSArray *tmpDirectoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:filePath error:nil];
            NSString *tmpItem;
            for (tmpItem in tmpDirectoryContent) {
                NSRange range = [tmpItem rangeOfString:@"(A Document Being Saved By" options:NSCaseInsensitiveSearch];
                if (range.location != NSNotFound) {
                    NSString *lastPath = [filePath stringByAppendingPathComponent:tmpItem];
                    NSError *error = nil;
                    [[NSFileManager defaultManager] removeItemAtPath:lastPath error:&error];
                    if (!error) {
                        NSLog(@"remove %@",lastPath);
                    }
                }
            }
        }
    }
}

- (void) initRoomView {
    [CouchBaseLiteLib listRoomByFilter:nil from:0 numberRow:NUMBER_ROW_PAGE];
    [CouchBaseLiteLib listRoomByKey:@"" andFilter:nil from:0 numberRow:NUMBER_ROW_PAGE];
}

- (void) initFilterView {
    [CouchBaseLiteLib listService];
    [CouchBaseLiteLib listBuildingByUnit:@"" from:0 numberRow:NUMBER_ROW_PAGE];
    [CouchBaseLiteLib listFloorsByBuilding:@""];
    [CouchBaseLiteLib listSystemByFilter:nil];
    [CouchBaseLiteLib getDocumentById:@""];
    [CouchBaseLiteLib getFloorByBuilding:@"" andFloorName:@""];
}

- (void) initEquipmentView {
    [CouchBaseLiteLib listEquipmentByKey:@"" andFilter:nil from:0 numberRow:NUMBER_ROW_PAGE];
}

- (void) initMaintenanceMgmtView {
    [CouchBaseLiteLib listInspectionFrom:0 numberRow:NUMBER_ROW_PAGE];
}

- (void) initSchedulingView {
    [ScheduleBaseLite queryListsInDatabase:[CouchBaseLiteLib sharedCouchBaseLite].database];
}

- (void) initContactMgmtView {
    [LiaisonBaseLite queryNewLiaisonByRole:@"" from:0 numberPage:NUMBER_ROW_PAGE];
}

- (void) initOtherViews {
    [CouchBaseLiteLib listMaintenanceAndInspectionByItem:@"" from:0 numberRow:NUMBER_ROW_PAGE];
    [CouchBaseLiteLib listDocumentAttachmentByItem:@""];
    [CouchBaseLiteLib listAttachmentByMaintenance:@"" andType:0];
    
    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"0",@"_id",@"0",@"itemId", nil];
    [CouchBaseLiteLib countUnreadSchedulingByItem:dict];
    [ScheduleBaseLite queryScheduleByItemId:dict from:0 numberPage:NUMBER_ROW_PAGE];
    [LiaisonBaseLite searchNewContactByKey:@"" from:0 numberPage:NUMBER_ROW_PAGE];
    [self listAllRole];
    
    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:@"isInitDesignView"];
}

- (void) initAllViews {
    [self initFilterView];
    [self initRoomView];
    [self initEquipmentView];
    [self initMaintenanceMgmtView];
    [self initSchedulingView];
    [self initContactMgmtView];
    [self initOtherViews];
}

#pragma mark user methods

- (int) countUser {
    CBLView* view = [[CouchBaseLiteLib sharedCouchBaseLite].database viewNamed: @"GetCountUser"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:@"User"])
                emit(doc, nil);
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    return [query.rows count];
}

- (NSMutableDictionary*) getUserByEmail:(NSString*)email {
    CBLQueryRow *userDocument = nil;
    //get all documents in table = "User"
    email = [email stringByReplacingOccurrencesOfString:@"%40"
                                             withString:@"@"];
    CBLView* view = [[CouchBaseLiteLib sharedCouchBaseLite].database viewNamed: @"GetUserEmail"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:@"User"]) {
                id userEmail = doc[@"email"];
                BOOL status  = [[doc objectForKey:@"status"] boolValue];
                if (userEmail && status)
                emit(CBLTextKey(userEmail), nil);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",email];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;

    for (CBLQueryRow *row in query.rows) {
//        if ([email isEqualToString:[row.document propertyForKey:@"email"]]){
            NSLog(@"row = %@ email = %@",row.documentID,[row.document propertyForKey:@"email"]);
            userDocument = row;
//            break;
//        }
    }
    return [userDocument.document.properties mutableCopy];
    
}
- (NSError *) updateUserAccount:(NSString*)accountAuth newDict:(NSMutableDictionary*)dict {
    // Save changes, asynchronously:
    NSString *idDocument = [dict objectForKey:@"_id"];
    NSError* error;
    CBLDocument *document = [self getDocumentById:idDocument];
    if (document)
    {
        int count = 0;
        [dict setObject:accountAuth forKey:@"passwordEncrypted"];
        do {
            [document putProperties:dict error:&error];
            count++;
        } while ([error.domain isEqualToString: CBLHTTPErrorDomain] &&error.code == 409 && count >= 3);
    }
    else{
        NSMutableDictionary *info = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"Couldn't get document to update",NSURLErrorFailingURLErrorKey, nil];
        error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:info];
    }
    return error;
}

#pragma mark Role Document

- (NSMutableDictionary *)getPermissionByRoleName:(NSString *)roleName{
    
    CBLQueryRow *userDocument = nil;
  
    CBLView* view = [[CouchBaseLiteLib sharedCouchBaseLite].database viewNamed: @"CheckPermissionByRoleName"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:RoleDoc])
                emit(doc[@"roleName"], nil);
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[roleName];
    for (CBLQueryRow *row in query.rows) {
        if ([[row.document propertyForKey:@"status"] intValue] == 1){
            userDocument = row;
            break;
        }
    }
    return [userDocument.document.properties mutableCopy];
    
}

- (NSMutableArray*) listAllRole {
    CBLView* view = [[CouchBaseLiteLib sharedCouchBaseLite].database viewNamed: @"CheckPermissionByRoleName"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:RoleDoc]) {
                emit(doc[@"roleName"], doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        if ([[[dict objectForKey:@"roleName"] lowercaseString] isEqualToString:@"admin"])
            continue;
        if ([[dict objectForKey:@"status"] intValue])
            [tmpArray addObject:dict];
    }
    return tmpArray;
}
#pragma mark methods document
- (NSError*) updateDoc:(CBLDocument*)doc withContent:(BOOL (^)(NSMutableDictionary* dict))block countTimer:(int)cnt{
    NSError* error;
    int count = 0;
    do {
        if (count == cnt)
        {
            NSDictionary *userInfo = [NSDictionary dictionaryWithObject:@"Error time out" forKey:NSURLErrorFailingURLErrorKey];
            return [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo];
        }
        NSMutableDictionary* props = [doc.properties mutableCopy];
        if (!props)
            props = [NSMutableDictionary dictionary];
        if (!block(props)) { // Invoke the callback to update the properties!
            return nil;
        }
        //update date updated
        [props setObject:[NSNumber numberWithLongLong:[[NSDate date] timeIntervalSince1970]] forKey:@"dateUpdated"];
        
        
        if ([doc putProperties: props error: &error]) {
            NSLog(@"Saved %@", doc);
            return nil; // success
        }
        count++;
    } while ((error.code == 409 && [error.domain isEqualToString: CBLHTTPErrorDomain]) || count > cnt);
    return error;
}

+ (CBLDocument*) getDocumentById:(NSString*)_documentId {
    CBLDocument *document = [[CouchBaseLiteLib sharedCouchBaseLite].database documentWithID:_documentId];
    return document;
}

+ (BOOL) addNewRoom:(CBLDatabase*)_database inputDict:(NSMutableDictionary*)_inputDict {
    BOOL isSuccess = NO;
    CBLDocument* doc = [_database untitledDocument];
    NSError* error;
    if (![doc putProperties:_inputDict error: &error]) {
        //add failed
    }
    else {
        isSuccess = YES;
    }
    
    return isSuccess;
}

+ (BOOL) updateRoom:(CBLDocument*)_document inputDict:(NSMutableDictionary*)_inputDict {
    BOOL isSuccess = NO;
    
    NSError* error;
    if (![_document putProperties:_inputDict error: &error]) {
        //update failed
    }
    else {
        isSuccess = YES;
    }
    
    return isSuccess;
}

//+ (NSMutableArray*) listRoomFrom:(int)from numberRow:(int)count {
//    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
//    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
//    CBLView* view = [_database viewNamed: @"listRoom"];
//    if (!view.mapBlock) {
//        // Register the map function, the first time we access the view:
//        [view setMapBlock: MAPBLOCK({
//            if ([doc[@"Table"] isEqualToString:BuildingMgmtDoc]) {
//                BOOL status = [[doc objectForKey:@"status"] boolValue];
//                if (status)
//                    emit(doc, nil);
//            }
//        }) reduceBlock: nil version: @"1.1"]; // bump version any time you change the MAPBLOCK body!
//    }
//    CBLQuery *query = [view query];
//    query.limit = count;
//    query.skip  = from;
//    
//    for (CBLQueryRow* row in query.rows) {
//        [tmpArray addObject:row.document.properties];
//    }
//    return tmpArray;
//}
//
//+ (NSMutableArray*) listRoomByContractor:(NSString*)_contractorId from:(int)from numberRow:(int)count {
//    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
//    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
//    CBLView* view = [_database viewNamed: @"listRoomByContractor"];
//    if (!view.mapBlock) {
//        // Register the map function, the first time we access the view:
//        [view setMapBlock: MAPBLOCK({
//            if ([doc[@"Table"] isEqualToString:BuildingMgmtDoc]) {
//                BOOL status = [[doc objectForKey:@"status"] boolValue];
//                id contractorId = [doc objectForKey:@"contractorId"];
//                if (status && contractorId)
//                    emit(contractorId, doc);
//            }
//        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
//    }
//    CBLQuery *query = [view query];
//    query.keys = @[_contractorId];
//    query.limit = count;
//    query.skip  = from;
//    
//    for (CBLQueryRow* row in query.rows) {
//        [tmpArray addObject:row.document.properties];
//    }
//    return tmpArray;
//}

+ (NSMutableArray*) listRoomByFilter:(NSMutableDictionary*)_filterDictValue from:(int)from numberRow:(int)count {
    //get all keys and values of filter dict value
    NSArray *allKeys    = [_filterDictValue allKeys];
    NSArray *allValues  = [_filterDictValue allValues];
    
    NSMutableArray *newFilterArray = [NSMutableArray arrayWithCapacity:1];
    for (int i=0;i < [allKeys count];i++) {
        NSString *value = [allValues objectAtIndex:i];
        if ([value isEqualToString:@"0"]);
        else {
            NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:value,@"value",[allKeys objectAtIndex:i],@"filterKeyName", nil];
            @try {
                [newFilterArray addObject:dict];
            }
            @catch (NSException *e) {
                NSLog(@"%@",e);
            }
        }
    }

    //start load data from database
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    
    /*
    CBLView* view = [_database viewNamed: @"listRoomByFilter"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: ^(NSDictionary *doc, CBLMapEmitBlock emit){
            if ([doc[@"Table"] isEqualToString:BuildingMgmtDoc]) {
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                id building = doc[@"building"];
                id camp     = doc[@"camp"];
                id floor    = doc[@"floor"];
                id service  = doc[@"service"];
                id unit     = doc[@"unit"];
                if (status == YES && building && camp && floor && service && unit){
                    emit(@[service,camp,unit,building,floor], doc);
                }
            }
        } reduceBlock: nil version:@"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    
    if (![[_filterDictValue objectForKey:@"service"] isEqualToString:@"0"]) {
        if (![[_filterDictValue objectForKey:@"camp"] isEqualToString:@"0"]) {
            if (![[_filterDictValue objectForKey:@"unit"] isEqualToString:@"0"]) {
                if (![[_filterDictValue objectForKey:@"building"] isEqualToString:@"0"]) {
                    if (![[_filterDictValue objectForKey:@"floor"] isEqualToString:@"0"]) {
                        //list by key service,camp,unit,building,floor
                        query.startKey = @[service,camp,unit,building,floor];
                        query.endKey   = @[service,camp,unit,building,floor];
                    }
                    else {
                        //list by key service,camp,unit,building
                        query.startKey = @[service,camp,unit,building];
                        query.endKey   = @[service,camp,unit,building,@{}];
                    }
                }
                else {
                    //list by key service,camp,unit
                    query.startKey = @[service,camp,unit];
                    query.endKey   = @[service,camp,unit,@{},@{}];
                }
            }
            else {
                //list by key service,camp
                query.startKey = @[service,camp];
                query.endKey   = @[service,camp,@{},@{},@{}];
            }
        }
        else {
            //list by key service
            query.startKey = @[service];
            query.endKey   = @[service,@{},@{},@{},@{}];
        }
    }
    else {
        //list all
    }
     */
    CBLView* view = [_database viewNamed: @"listItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            BOOL status = [[doc objectForKey:@"status"] boolValue];
            id contractorId = doc[@"contractorId"];
            id building = doc[@"building"];
            id camp     = doc[@"camp"];
            id floor    = doc[@"floor"];
            id service  = doc[@"service"];
            id unit     = doc[@"unit"];
            id room     = doc[@"room"] == nil ? @"0" : doc[@"room"];
            id system   = doc[@"system"] == nil ? @"" : doc[@"system"];
            id description = doc[@"description"] == nil ? @"" : doc[@"description"];
            id table = doc[@"Table"];
            if (table && status && contractorId && building && camp && floor && service && unit && system && description) {
                emit(@[table,service,camp,unit,building,floor,room,system,description,contractorId],doc);
            }
        }) reduceBlock: nil version:@"1.4"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.limit = count;
    query.skip  = from;
//    query.descending = NO;
    NSString *service   = [_filterDictValue objectForKey:@"service"] == nil ? @"0" : [_filterDictValue objectForKey:@"service"];
    NSString *camp      = [_filterDictValue objectForKey:@"camp"] == nil ? @"0" : [_filterDictValue objectForKey:@"camp"];
    NSString *unit      = [_filterDictValue objectForKey:@"unit"] == nil ? @"0" : [_filterDictValue objectForKey:@"unit"];
    NSString *building  = [_filterDictValue objectForKey:@"building"] == nil ? @"0" : [_filterDictValue objectForKey:@"building"];
    NSString *floor     = [_filterDictValue objectForKey:@"floor"] == nil ? @"0" : [_filterDictValue objectForKey:@"floor"];
    
    if (![[_filterDictValue objectForKey:@"service"] isEqualToString:@"0"]) {
        if (![[_filterDictValue objectForKey:@"camp"] isEqualToString:@"0"]) {
            if (![[_filterDictValue objectForKey:@"unit"] isEqualToString:@"0"]) {
                if (![[_filterDictValue objectForKey:@"building"] isEqualToString:@"0"]) {
                    if (![[_filterDictValue objectForKey:@"floor"] isEqualToString:@"0"]) {
                        //list by key service,camp,unit,building,floor
                        query.startKey = @[BuildingMgmtDoc,service,camp,unit,building,floor];
                        query.endKey   = @[BuildingMgmtDoc,service,camp,unit,building,floor,@{},@{},@{},@{}];
                    }
                    else {
                        //list by key service,camp,unit,building
                        query.startKey = @[BuildingMgmtDoc,service,camp,unit,building];
                        query.endKey   = @[BuildingMgmtDoc,service,camp,unit,building,@{},@{},@{},@{},@{}];
                    }
                }
                else {
                    //list by key service,camp,unit
                    query.startKey = @[BuildingMgmtDoc,service,camp,unit];
                    query.endKey   = @[BuildingMgmtDoc,service,camp,unit,@{},@{},@{},@{},@{},@{}];
                }
            }
            else {
                //list by key service,camp
                query.startKey = @[BuildingMgmtDoc,service,camp];
                query.endKey   = @[BuildingMgmtDoc,service,camp,@{},@{},@{},@{},@{},@{},@{}];
            }
        }
        else {
            //list by key service
            query.startKey = @[BuildingMgmtDoc,service];
            query.endKey   = @[BuildingMgmtDoc,service,@{},@{},@{},@{},@{},@{},@{},@{}];
        }
    }
    else {
        //list all
        query.startKey = @[BuildingMgmtDoc];
        query.endKey   = @[BuildingMgmtDoc,@{},@{},@{},@{},@{},@{},@{},@{},@{},@{}];
    }
    for (CBLQueryRow* row in query.rows) {
        @try {
            if (row.document.properties != nil)
                [tmpArray addObject:row.document.properties];
        }
        @catch (NSException *e) {
            NSLog(@"%@",e);
        }
    }
    return tmpArray;
}

+ (NSMutableArray*) listRoomByKey:(NSString*)_searchKey andFilter:(NSMutableDictionary*)_filterDictValue from:(int)from numberRow:(int)count {
    //get all keys and values of filter dict value
    NSArray *allKeys    = [_filterDictValue allKeys];
    NSArray *allValues  = [_filterDictValue allValues];
    
    //check if value != 0, add to array to filter
    NSMutableArray *newFilterArray = [NSMutableArray arrayWithCapacity:1];
    for (int i=0;i < [allKeys count];i++) {
        NSString *value = [allValues objectAtIndex:i];
        if ([value isEqualToString:@"0"]);
        else {
            NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:value,@"value",[allKeys objectAtIndex:i],@"filterKeyName", nil];
            [newFilterArray addObject:dict];
        }
    }
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listRoomByKey"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:BuildingMgmtDoc]) {
                id name = [[doc objectForKey:@"item_name"] lowercaseString];
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                if (status && name) {
                    emit(CBLTextKey(name),doc);
                }
            }
        }) reduceBlock: nil version:@"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@*",_searchKey];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    query.limit = count;
    query.skip  = from;
//    query.descending = NO;
    
//    NSString *service   = [_filterDictValue objectForKey:@"service"];
//    NSString *camp      = [_filterDictValue objectForKey:@"camp"];
//    NSString *unit      = [_filterDictValue objectForKey:@"unit"];
//    NSString *building  = [_filterDictValue objectForKey:@"building"];
//    NSString *floor     = [_filterDictValue objectForKey:@"floor"];
    
//    if (![[_filterDictValue objectForKey:@"service"] isEqualToString:@"0"]) {
//        if (![[_filterDictValue objectForKey:@"camp"] isEqualToString:@"0"]) {
//            if (![[_filterDictValue objectForKey:@"unit"] isEqualToString:@"0"]) {
//                if (![[_filterDictValue objectForKey:@"building"] isEqualToString:@"0"]) {
//                    if (![[_filterDictValue objectForKey:@"floor"] isEqualToString:@"0"]) {
//                        //list by key service,camp,unit,building,floor
//                        query.startKey = @[_searchKey,service,camp,unit,building,floor];
//                        query.endKey   = @[_searchKey,service,camp,unit,building,floor];
//                    }
//                    else {
//                        //list by key service,camp,unit,building
//                        query.startKey = @[_searchKey,service,camp,unit,building];
//                        query.endKey   = @[_searchKey,service,camp,unit,building,@{}];
//                    }
//                }
//                else {
//                    //list by key service,camp,unit
//                    query.startKey = @[_searchKey,service,camp,unit];
//                    query.endKey   = @[_searchKey,service,camp,unit,@{},@{}];
//                }
//            }
//            else {
//                //list by key service,camp
//                query.startKey = @[_searchKey,service,camp];
//                query.endKey   = @[_searchKey,service,camp,@{},@{},@{}];
//            }
//        }
//        else {
//            //list by key service
//            query.startKey = @[_searchKey,service];
//            query.endKey   = @[_searchKey,service,@{},@{},@{},@{}];
//        }
//    }
//    else {
//        //list all
//        query.startKey = @[_searchKey];
//        query.endKey   = @[_searchKey,@{},@{},@{},@{},@{}];
//    }
    
    for (CBLQueryRow* row in query.rows) {
        @try {
            [tmpArray addObject:row.document.properties];
        }
        @catch (NSException *e) {
            NSLog(@"%@",e);
        }
    }
    
    return tmpArray;
}

+ (NSMutableArray*) listRoomByFilter:(NSMutableDictionary*)_filterDictValue contractor:(NSString*)_contractorId from:(int)from numberRow:(int)count {
    //get all keys and values of filter dict value
    NSArray *allKeys    = [_filterDictValue allKeys];
    NSArray *allValues  = [_filterDictValue allValues];
    
    NSMutableArray *newFilterArray = [NSMutableArray arrayWithCapacity:1];
    for (int i=0;i < [allKeys count];i++) {
        NSString *value = [allValues objectAtIndex:i];
        if ([value isEqualToString:@"0"]);
        else {
            NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:value,@"value",[allKeys objectAtIndex:i],@"filterKeyName", nil];
            [newFilterArray addObject:dict];
        }
    }
    
    //start load data from database
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    /*
    CBLView* view = [_database viewNamed: @"listRoomByFilterAndContractor"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:BuildingMgmtDoc]) {
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                id contractorId = doc[@"contractorId"];
                id building = doc[@"building"];
                id camp     = doc[@"camp"];
                id floor    = doc[@"floor"];
                id service  = doc[@"service"];
                id unit     = doc[@"unit"];
                if (status && contractorId && building && camp && floor && service && unit) {
                    emit(@[contractorId,service,camp,unit,building,floor],doc);
                }
            }
        }) reduceBlock: nil version:@"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
     */
    
    CBLView* view = [_database viewNamed: @"listItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            BOOL status = [[doc objectForKey:@"status"] boolValue];
            id contractorId = doc[@"contractorId"];
            id building = doc[@"building"];
            id camp     = doc[@"camp"];
            id floor    = doc[@"floor"];
            id service  = doc[@"service"];
            id unit     = doc[@"unit"];
            id room     = doc[@"room"] == nil ? @"0" : doc[@"room"];
            id system   = doc[@"system"] == nil ? @"" : doc[@"system"];
            id description = doc[@"description"] == nil ? @"" : doc[@"description"];
            id table = doc[@"Table"];
            if (table && status && contractorId && building && camp && floor && service && unit && system && description) {
                emit(@[table,service,camp,unit,building,floor,room,system,description,contractorId],doc);
            }
        }) reduceBlock: nil version:@"1.4"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.limit = count;
    query.skip  = from;
    
    NSString *service   = [_filterDictValue objectForKey:@"service"] == nil ? @"0" : [_filterDictValue objectForKey:@"service"];
    NSString *camp      = [_filterDictValue objectForKey:@"camp"] == nil ? @"0" : [_filterDictValue objectForKey:@"camp"];
    NSString *unit      = [_filterDictValue objectForKey:@"unit"] == nil ? @"0" : [_filterDictValue objectForKey:@"unit"];
    NSString *building  = [_filterDictValue objectForKey:@"building"] == nil ? @"0" : [_filterDictValue objectForKey:@"building"];
    NSString *floor     = [_filterDictValue objectForKey:@"floor"] == nil ? @"0" : [_filterDictValue objectForKey:@"floor"];
    
    if (![[_filterDictValue objectForKey:@"service"] isEqualToString:@"0"]) {
        if (![[_filterDictValue objectForKey:@"camp"] isEqualToString:@"0"]) {
            if (![[_filterDictValue objectForKey:@"unit"] isEqualToString:@"0"]) {
                if (![[_filterDictValue objectForKey:@"building"] isEqualToString:@"0"]) {
                    if (![[_filterDictValue objectForKey:@"floor"] isEqualToString:@"0"]) {
                        //list by key service,camp,unit,building,floor
                        query.startKey = @[BuildingMgmtDoc,service,camp,unit,building,floor];
                        query.endKey   = @[BuildingMgmtDoc,service,camp,unit,building,floor,@{},@{},@{},_contractorId];
                    }
                    else {
                        //list by key service,camp,unit,building
                        query.startKey = @[BuildingMgmtDoc,service,camp,unit,building];
                        query.endKey   = @[BuildingMgmtDoc,service,camp,unit,building,@{},@{},@{},@{},_contractorId];
                    }
                }
                else {
                    //list by key service,camp,unit
                    query.startKey = @[BuildingMgmtDoc,service,camp,unit];
                    query.endKey   = @[BuildingMgmtDoc,service,camp,unit,@{},@{},@{},@{},@{},_contractorId];
                }
            }
            else {
                //list by key service,camp
                query.startKey = @[BuildingMgmtDoc,service,camp];
                query.endKey   = @[BuildingMgmtDoc,service,camp,@{},@{},@{},@{},@{},@{},_contractorId];
            }
        }
        else {
            //list by key service
            query.startKey = @[BuildingMgmtDoc,service];
            query.endKey   = @[BuildingMgmtDoc,service,@{},@{},@{},@{},@{},@{},@{},_contractorId];
        }
    }
    else {
        //list all
        query.startKey = @[BuildingMgmtDoc];
        query.endKey   = @[BuildingMgmtDoc,@{},@{},@{},@{},@{},@{},@{},@{},_contractorId];
    }
    
    for (CBLQueryRow* row in query.rows) {
        @try {
            [tmpArray addObject:row.document.properties];
        }
        @catch (NSException *e) {
            NSLog(@"%@",e);
        }
    }

    return tmpArray;
}

+ (NSMutableArray*) listRoomByKey:(NSString*)_searchKey andFilter:(NSMutableDictionary*)_filterDictValue contractor:(NSString*)_contractorId from:(int)from numberRow:(int)count {
    
    //get all keys and values of filter dict value
    NSArray *allKeys    = [_filterDictValue allKeys];
    NSArray *allValues  = [_filterDictValue allValues];
    
    //check if value != 0, add to array to filter
    NSMutableArray *newFilterArray = [NSMutableArray arrayWithCapacity:1];
    for (int i=0;i < [allKeys count];i++) {
        NSString *value = [allValues objectAtIndex:i];
        if ([value isEqualToString:@"0"]);
        else {
            NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:value,@"value",[allKeys objectAtIndex:i],@"filterKeyName", nil];
            [newFilterArray addObject:dict];
        }
    }
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listRoomByKeyAndContractor"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:BuildingMgmtDoc]) {
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                id contractorId = [doc objectForKey:@"contractorId"];
                id name     = [doc objectForKey:@"item_name"];
//                id building = doc[@"building"];
//                id camp     = doc[@"camp"];
//                id floor    = doc[@"floor"];
//                id service  = doc[@"service"];
//                id unit     = doc[@"unit"];
                if (status && contractorId) {
//                    emit(@[contractorId,name,service,camp,unit,building,floor],doc);
                    emit(CBLTextKey(name),doc);
                }
            }
        }) reduceBlock: nil version:@"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@*",_searchKey];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    query.limit = count;
    query.skip  = from;
    
//    NSString *service   = [_filterDictValue objectForKey:@"service"];
//    NSString *camp      = [_filterDictValue objectForKey:@"camp"];
//    NSString *unit      = [_filterDictValue objectForKey:@"unit"];
//    NSString *building  = [_filterDictValue objectForKey:@"building"];
//    NSString *floor     = [_filterDictValue objectForKey:@"floor"];
//    
//    if (![[_filterDictValue objectForKey:@"service"] isEqualToString:@"0"]) {
//        if (![[_filterDictValue objectForKey:@"camp"] isEqualToString:@"0"]) {
//            if (![[_filterDictValue objectForKey:@"unit"] isEqualToString:@"0"]) {
//                if (![[_filterDictValue objectForKey:@"building"] isEqualToString:@"0"]) {
//                    if (![[_filterDictValue objectForKey:@"floor"] isEqualToString:@"0"]) {
//                        //list by key service,camp,unit,building,floor
//                        query.startKey = @[_contractorId,_searchKey,service,camp,unit,building,floor];
//                        query.endKey   = @[_contractorId,_searchKey,service,camp,unit,building,floor];
//                    }
//                    else {
//                        //list by key service,camp,unit,building
//                        query.startKey = @[_contractorId,_searchKey,service,camp,unit,building];
//                        query.endKey   = @[_contractorId,_searchKey,service,camp,unit,building,@{}];
//                    }
//                }
//                else {
//                    //list by key service,camp,unit
//                    query.startKey = @[_contractorId,_searchKey,service,camp,unit];
//                    query.endKey   = @[_contractorId,_searchKey,service,camp,unit,@{},@{}];
//                }
//            }
//            else {
//                //list by key service,camp
//                query.startKey = @[_contractorId,_searchKey,service,camp];
//                query.endKey   = @[_contractorId,_searchKey,service,camp,@{},@{},@{}];
//            }
//        }
//        else {
//            //list by key service
//            query.startKey = @[_contractorId,_searchKey,service];
//            query.endKey   = @[_contractorId,_searchKey,service,@{},@{},@{},@{}];
//        }
//    }
//    else {
//        //list all
//        query.startKey = @[_contractorId,_searchKey];
//        query.endKey   = @[_contractorId,_searchKey,@{},@{},@{},@{},@{}];
//    }
    
    for (CBLQueryRow* row in query.rows) {
        [tmpArray addObject:row.document.properties];
    }

    return tmpArray;
}

- (CBLDocument*) createDocumentWithAttachment:(NSMutableDictionary*)content fileData:(NSData*)fileData error:(NSError **)error {
    CBLDocument *document = [self.database untitledDocument];
    
    [content setObject:[NSNumber numberWithLongLong:[[NSDate date] timeIntervalSince1970]] forKey:@"dateUpdated"];
    
//    CBLNewRevision *rev = document.newRevision;
//    [rev.properties addEntriesFromDictionary:content];
//    [rev save:error];
    
    if ([document putProperties:content error:error]) {
        if (fileData != nil) {
            CBLAttachment* attachment = [[CBLAttachment alloc] initWithContentType:@"image/png" body:fileData];
            if (document.currentRevision) {
                CBLNewRevision* newRevision = [document.currentRevision newRevision];
                if (attachment) {
                    [newRevision addAttachment:attachment named:[content objectForKey:@"fileName"]];
                    NSError* err;
                    if (![newRevision save:&err])
                    {
                        NSLog(@"CBLNewRevision save attachment error: %@", [err description]);
                    }
                }
                [content setObject:document.documentID forKey:@"_id"];
                [content setObject:document.currentRevisionID forKey:@"_rev"];
            }
        }
    }

    return document;
}

// create document with argument content and error
- (CBLDocument *)createDocument:(NSMutableDictionary *)content error:(NSError **)error{
    
    CBLDocument *document = [self.database untitledDocument];
    
    [content setObject:[NSNumber numberWithLongLong:[[NSDate date] timeIntervalSince1970]] forKey:@"dateUpdated"];
    
    CBLNewRevision *rev = document.newRevision;
    [rev.properties addEntriesFromDictionary:content];
    [rev save:error];
    
//    [[document putProperties:content error:error].newRevision save:error];
    [content setObject:document.documentID forKey:@"_id"];
    [content setObject:document.currentRevisionID forKey:@"_rev"];
    
    return document;
}

// update document with argument content and error
- (CBLDocument *)updateDocument:(NSMutableDictionary *)content error:(NSError **)error{
    
    [content setObject:[NSNumber numberWithLongLong:[[NSDate date] timeIntervalSince1970]] forKey:@"dateUpdated"];
    
    NSString *idDocument = [content objectForKey:@"_id"];
    CBLDocument *document = [self getDocumentById:idDocument];
    if (document)
    {
        int count = 0;
        do {
            [content setObject:document.currentRevisionID forKey:@"_rev"];
            [document putProperties:content error:error];
            count++;
        } while ([(*error).domain isEqualToString: CBLHTTPErrorDomain] &&(*error).code == 409 && count >= 3);
    }
    else{
        NSMutableDictionary *info = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"Couldn't get document to update",NSURLErrorFailingURLErrorKey, nil];
        *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:info];
    }
    return document;
}

// get document by id document
- (CBLDocument *)getDocumentById:(NSString *)idDocument{
    CBLDocument *document = [self.database documentWithID:idDocument];
    return document;
}
// delete document
- (void)deleteDocumentById:(NSString *)idDocument error:(NSError **)error{
    
    CBLDocument *document = [self getDocumentById:idDocument];
    if (document)
        [document deleteDocument:error];
    else{
        NSMutableDictionary *info = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"Couldn't get document to delete",NSURLErrorFailingURLErrorKey, nil];
        *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:info];
    }
    
}

#pragma mark FACILITY
+ (BOOL) addNewEquipment:(CBLDatabase*)_database inputDict:(NSMutableDictionary*)_inputDict {
    BOOL isSuccess = NO;
    CBLDocument* doc = [_database untitledDocument];
    NSError* error;
    if (![doc putProperties:_inputDict error: &error]) {
        //add failed
    }
    else {
        isSuccess = YES;
    }
    
    return isSuccess;
}
+ (BOOL) updateEquipment:(CBLDocument*)_document inputDict:(NSMutableDictionary*)_inputDict {
    BOOL isSuccess = NO;
    
    NSError* error;
    if (![_document putProperties:_inputDict error: &error]) {
        //update failed
    }
    else {
        isSuccess = YES;
    }
    
    return isSuccess;
}
//+ (NSMutableArray*) listEquipment {
//    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
//    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
//    CBLView* view = [_database viewNamed: @"listEquipment"];
//    if (!view.mapBlock) {
//        // Register the map function, the first time we access the view:
//        [view setMapBlock: MAPBLOCK({
//            if ([doc[@"Table"] isEqualToString:FacilityMgmtDoc])
//                emit(doc, nil);
//        }) reduceBlock: nil version: @"1"]; // bump version any time you change the MAPBLOCK body!
//    }
//    CBLQuery *query = [view query];
//    
//    for (CBLQueryRow* row in query.rows) {
//        [tmpArray addObject:row.document.properties];
//    }
//    return tmpArray;
//}

+ (NSMutableArray*) listEquipmentByFilter:(NSMutableDictionary*)_filterDictValue from:(int)from numberRow:(int)count {
    
    @try {
        //get all keys and values of filter dict value
        NSArray *allKeys    = [_filterDictValue allKeys];
        NSArray *allValues  = [_filterDictValue allValues];
        
        //check if value != 0, add to array to filter
        NSMutableArray *newFilterArray = [NSMutableArray arrayWithCapacity:1];
        for (int i=0;i < [allKeys count];i++) {
            NSString *value = [allValues objectAtIndex:i];
            if ([value isEqualToString:@"0"]);
            else {
                NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:value,@"value",[allKeys objectAtIndex:i],@"filterKeyName", nil];
                [newFilterArray addObject:dict];
            }
        }
    }
    @catch (NSException *e) {
        NSLog(@"%@",e);
    }
    
    //start load data from database
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    /*
    CBLView* view = [_database viewNamed: @"listEquipmentByFilter"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:FacilityMgmtDoc]) {
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                id building = doc[@"building"];
                id camp     = doc[@"camp"];
                id floor    = doc[@"floor"] == nil ? @"0" : doc[@"floor"];
                id service  = doc[@"service"];
                id unit     = doc[@"unit"];
                id room     = doc[@"room"] == nil ? @"0" : doc[@"room"];
                id system   = doc[@"system"];
                id description = doc[@"description"];
                
                if (status && building && camp && service && unit && system && description) {
                    emit(@[service,camp,unit,building,floor,room,system,description], doc);
                }
            }
        }) reduceBlock: nil version:@"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
     */
    CBLView* view = [_database viewNamed: @"listItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            BOOL status = [[doc objectForKey:@"status"] boolValue];
            id contractorId = doc[@"contractorId"];
            id building = doc[@"building"];
            id camp     = doc[@"camp"];
            id floor    = doc[@"floor"];
            id service  = doc[@"service"];
            id unit     = doc[@"unit"];
            id room     = doc[@"room"] == nil ? @"0" : doc[@"room"];
            id system   = doc[@"system"] == nil ? @"" : doc[@"system"];
            id description = doc[@"description"] == nil ? @"" : doc[@"description"];
            id table = doc[@"Table"];
            if (table && status && contractorId && building && camp && floor && service && unit && system && description) {
                emit(@[table,service,camp,unit,building,floor,room,system,description,contractorId],doc);
            }
        }) reduceBlock: nil version:@"1.4"]; // bump version any time you change the MAPBLOCK body!
    }
    
    CBLQuery *query = [view query];
    query.limit = count;
    query.skip  = from;
//    query.descending = NO;
    
    NSString *service   = [_filterDictValue objectForKey:@"service"] == nil ? @"0" : [_filterDictValue objectForKey:@"service"];
    NSString *camp      = [_filterDictValue objectForKey:@"camp"] == nil ? @"0" : [_filterDictValue objectForKey:@"camp"];
    NSString *unit      = [_filterDictValue objectForKey:@"unit"] == nil ? @"0" : [_filterDictValue objectForKey:@"unit"];
    NSString *building  = [_filterDictValue objectForKey:@"building"] == nil ? @"0" : [_filterDictValue objectForKey:@"building"];
    NSString *floor     = [_filterDictValue objectForKey:@"floor"] == nil ? @"0" : [_filterDictValue objectForKey:@"floor"];
    NSString *room      = [_filterDictValue objectForKey:@"room"] == nil ? @"0" : [_filterDictValue objectForKey:@"room"];
    NSString *system    = [_filterDictValue objectForKey:@"system"] == nil ? @"0" : [_filterDictValue objectForKey:@"system"];
    NSString *description = [_filterDictValue objectForKey:@"description"] == nil ? @"0" : [_filterDictValue objectForKey:@"description"];
    
    if (![[_filterDictValue objectForKey:@"service"] isEqualToString:@"0"]) {
        if (![[_filterDictValue objectForKey:@"camp"] isEqualToString:@"0"]) {
            if (![[_filterDictValue objectForKey:@"unit"] isEqualToString:@"0"]) {
                if (![[_filterDictValue objectForKey:@"building"] isEqualToString:@"0"]) {
                    if (![[_filterDictValue objectForKey:@"floor"] isEqualToString:@"0"]) {
                        if (![[_filterDictValue objectForKey:@"room"] isEqualToString:@"0"]) {
                            if (![[_filterDictValue objectForKey:@"system"] isEqualToString:@"0"]) {
                                if (![[_filterDictValue objectForKey:@"description"] isEqualToString:@"0"]) {
                                    query.startKey = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,system,description];
                                    query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,system,description,@{}];
                                }
                                else {
                                    query.startKey = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,system];
                                    query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,system,@{},@{}];
                                }
                            }
                            else {
                                query.startKey = @[FacilityMgmtDoc,service,camp,unit,building,floor,room];
                                query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,@{},@{},@{}];
                            }
                        }
                        else {
                            //list by key service,camp,unit,building,floor
                            query.startKey = @[FacilityMgmtDoc,service,camp,unit,building,floor];
                            query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,floor,@{},@{},@{},@{}];
                        }
                    }
                    else {
                        //list by key service,camp,unit,building
                        query.startKey = @[FacilityMgmtDoc,service,camp,unit,building];
                        query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,@{},@{},@{},@{},@{}];
                    }
                }
                else {
                    //list by key service,camp,unit
                    query.startKey = @[FacilityMgmtDoc,service,camp,unit];
                    query.endKey   = @[FacilityMgmtDoc,service,camp,unit,@{},@{},@{},@{},@{},@{}];
                }
            }
            else {
                //list by key service,camp
                query.startKey = @[FacilityMgmtDoc,service,camp];
                query.endKey   = @[FacilityMgmtDoc,service,camp,@{},@{},@{},@{},@{},@{},@{}];
            }
        }
        else {
            //list by key service
            query.startKey = @[FacilityMgmtDoc,service];
            query.endKey   = @[FacilityMgmtDoc,service,@{},@{},@{},@{},@{},@{},@{},@{}];
        }
    }
    else {
        query.startKey = @[FacilityMgmtDoc];
        query.endKey   = @[FacilityMgmtDoc,@{},@{},@{},@{},@{},@{},@{},@{},@{}];
    }
    
    for (CBLQueryRow* row in query.rows) {
        @try {
            [tmpArray addObject:row.document.properties];
        }
        @catch (NSException *e) {
            NSLog(@"%@",e);
        }
    }
    
    return tmpArray;
}

+ (NSMutableArray*) listEquipmentByKey:(NSString*)_searchKey andFilter:(NSMutableDictionary*)_filterDictValue from:(int)from numberRow:(int)count {
    
    //get all keys and values of filter dict value
    NSArray *allKeys    = [_filterDictValue allKeys];
    NSArray *allValues  = [_filterDictValue allValues];
    
    //check if value != 0, add to array to filter
    NSMutableArray *newFilterArray = [NSMutableArray arrayWithCapacity:1];
    for (int i=0;i < [allKeys count];i++) {
        NSString *value = [allValues objectAtIndex:i];
        if ([value isEqualToString:@"0"]);
        else {
            NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:value,@"value",[allKeys objectAtIndex:i],@"filterKeyName", nil];
            [newFilterArray addObject:dict];
        }
    }
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listEquipmentByKey"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:FacilityMgmtDoc]) {
                id name = [doc objectForKey:@"item_name"];
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                
                if (status && name) {
                    emit(CBLTextKey(name),doc);
                }
            }
        }) reduceBlock: nil version:@"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@*",_searchKey];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    query.limit = count;
    query.skip  = from;
//    query.descending = NO;
    
    for (CBLQueryRow* row in query.rows) {
        [tmpArray addObject:row.document.properties];
    }
    
    return tmpArray;
}

+ (NSMutableArray*) listEquipmentByFilter:(NSMutableDictionary*)_filterDictValue contractor:(NSString*)_contractorId from:(int)from numberRow:(int)count {
    //get all keys and values of filter dict value
    NSArray *allKeys    = [_filterDictValue allKeys];
    NSArray *allValues  = [_filterDictValue allValues];
    
    //check if value != 0, add to array to filter
    NSMutableArray *newFilterArray = [NSMutableArray arrayWithCapacity:1];
    for (int i=0;i < [allKeys count];i++) {
        NSString *value = [allValues objectAtIndex:i];
        if ([value isEqualToString:@"0"]);
        else {
            NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:value,@"value",[allKeys objectAtIndex:i],@"filterKeyName", nil];
            [newFilterArray addObject:dict];
        }
    }
    
    //start load data from database
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    /*
    CBLView* view = [_database viewNamed: @"listEquipmentByFilterAndContractor"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:FacilityMgmtDoc]) {
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                NSString *contractorId = [doc objectForKey:@"contractorId"];
                id building = doc[@"building"];
                id camp     = doc[@"camp"];
                id floor    = doc[@"floor"];
                id service  = doc[@"service"];
                id unit     = doc[@"unit"];
                id room     = doc[@"room"];
                id system   = doc[@"system"];
                id description = doc[@"description"];
                
                if (status && contractorId && building && camp && floor && service && unit && room && system && description) {
                    emit(@[contractorId,service,camp,unit,building,floor,room,system,description], doc);
                }
            }
        }) reduceBlock: nil version:@"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
     */
    CBLView* view = [_database viewNamed: @"listItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            BOOL status = [[doc objectForKey:@"status"] boolValue];
            id contractorId = doc[@"contractorId"];
            id building = doc[@"building"];
            id camp     = doc[@"camp"];
            id floor    = doc[@"floor"];
            id service  = doc[@"service"];
            id unit     = doc[@"unit"];
            id room     = doc[@"room"] == nil ? @"0" : doc[@"room"];
            id system   = doc[@"system"] == nil ? @"" : doc[@"system"];
            id description = doc[@"description"] == nil ? @"" : doc[@"description"];
            id table = doc[@"Table"];
            if (table && status && contractorId && building && camp && floor && service && unit && system && description) {
                emit(@[table,service,camp,unit,building,floor,room,system,description,contractorId],doc);
            }
        }) reduceBlock: nil version:@"1.4"]; // bump version any time you change the MAPBLOCK body!
    }
    
    CBLQuery *query = [view query];

    query.limit = count;
    query.skip  = from;
    
    NSString *service   = [_filterDictValue objectForKey:@"service"] == nil ? @"0" : [_filterDictValue objectForKey:@"service"];
    NSString *camp      = [_filterDictValue objectForKey:@"camp"] == nil ? @"0" : [_filterDictValue objectForKey:@"camp"];
    NSString *unit      = [_filterDictValue objectForKey:@"unit"] == nil ? @"0" : [_filterDictValue objectForKey:@"unit"];
    NSString *building  = [_filterDictValue objectForKey:@"building"] == nil ? @"0" : [_filterDictValue objectForKey:@"building"];
    NSString *floor     = [_filterDictValue objectForKey:@"floor"] == nil ? @"0" : [_filterDictValue objectForKey:@"floor"];
    NSString *room      = [_filterDictValue objectForKey:@"room"] == nil ? @"0" : [_filterDictValue objectForKey:@"room"];
    NSString *system    = [_filterDictValue objectForKey:@"system"] == nil ? @"0" : [_filterDictValue objectForKey:@"system"];
    NSString *description = [_filterDictValue objectForKey:@"description"] == nil ? @"0" : [_filterDictValue objectForKey:@"description"];
    
    if (![[_filterDictValue objectForKey:@"service"] isEqualToString:@"0"]) {
        if (![[_filterDictValue objectForKey:@"camp"] isEqualToString:@"0"]) {
            if (![[_filterDictValue objectForKey:@"unit"] isEqualToString:@"0"]) {
                if (![[_filterDictValue objectForKey:@"building"] isEqualToString:@"0"]) {
                    if (![[_filterDictValue objectForKey:@"floor"] isEqualToString:@"0"]) {
                        if (![[_filterDictValue objectForKey:@"room"] isEqualToString:@"0"]) {
                            if (![[_filterDictValue objectForKey:@"system"] isEqualToString:@"0"]) {
                                if (![[_filterDictValue objectForKey:@"description"] isEqualToString:@"0"]) {
                                    query.startKey = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,system,description,_contractorId];
                                    query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,system,description,_contractorId];
                                }
                                else {
                                    query.startKey = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,system];
                                    query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,system,@{},_contractorId];
                                }
                            }
                            else {
                                query.startKey = @[FacilityMgmtDoc,service,camp,unit,building,floor,room];
                                query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,floor,room,@{},@{},_contractorId];
                            }
                        }
                        else {
                            //list by key service,camp,unit,building,floor
                            query.startKey = @[FacilityMgmtDoc,service,camp,unit,building,floor];
                            query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,floor,@{},@{},@{},_contractorId];
                        }
                    }
                    else {
                        //list by key service,camp,unit,building
                        query.startKey = @[FacilityMgmtDoc,service,camp,unit,building];
                        query.endKey   = @[FacilityMgmtDoc,service,camp,unit,building,@{},@{},@{},@{},_contractorId];
                    }
                }
                else {
                    //list by key service,camp,unit
                    query.startKey = @[FacilityMgmtDoc,service,camp,unit];
                    query.endKey   = @[FacilityMgmtDoc,service,camp,unit,@{},@{},@{},@{},@{},_contractorId];
                }
            }
            else {
                //list by key service,camp
                query.startKey = @[FacilityMgmtDoc,service,camp];
                query.endKey   = @[FacilityMgmtDoc,service,camp,@{},@{},@{},@{},@{},@{},_contractorId];
            }
        }
        else {
            //list by key service
            query.startKey = @[FacilityMgmtDoc,service];
            query.endKey   = @[FacilityMgmtDoc,service,@{},@{},@{},@{},@{},@{},@{},_contractorId];
        }
    }
    else {
        query.startKey = @[FacilityMgmtDoc];
        query.endKey   = @[FacilityMgmtDoc,@{},@{},@{},@{},@{},@{},@{},@{},_contractorId];
    }
    
    for (CBLQueryRow* row in query.rows) {
        @try {
            [tmpArray addObject:row.document.properties];
        }
        @catch (NSException *e) {
            NSLog(@"%@",e);
        }
    }
    
    return tmpArray;
}

+ (NSMutableArray*) listEquipmentByKey:(NSString*)_searchKey andFilter:(NSMutableDictionary*)_filterDictValue contractor:(NSString*)_contractorId from:(int)from numberRow:(int)count {
    
    //get all keys and values of filter dict value
    NSArray *allKeys    = [_filterDictValue allKeys];
    NSArray *allValues  = [_filterDictValue allValues];
    
    //check if value != 0, add to array to filter
    NSMutableArray *newFilterArray = [NSMutableArray arrayWithCapacity:1];
    for (int i=0;i < [allKeys count];i++) {
        NSString *value = [allValues objectAtIndex:i];
        if ([value isEqualToString:@"0"]);
        else {
            NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:value,@"value",[allKeys objectAtIndex:i],@"filterKeyName", nil];
            [newFilterArray addObject:dict];
        }
    }
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listEquipmentByKeyAndContractor"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:FacilityMgmtDoc]) {
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                NSString *contractorId = [doc objectForKey:@"contractorId"];
                id name = [doc objectForKey:@"item_name"];
                id building = doc[@"building"];
                id camp     = doc[@"camp"];
                id floor    = doc[@"floor"];
                id service  = doc[@"service"];
                id unit     = doc[@"unit"];
                id room     = doc[@"room"];
                id system   = doc[@"system"];
                id description = doc[@"description"];
                if (status && contractorId){
                    emit(@[contractorId,name,service,camp,unit,building,floor,room,system,description],doc);
                }
            }
        }) reduceBlock: nil version:@"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[_contractorId];
    query.limit = count;
    query.skip  = from;
    
    for (CBLQueryRow* row in query.rows) {
        [tmpArray addObject:row.document.properties];
    }
    
    return tmpArray;
}

+ (BOOL) addNewInspection:(NSMutableDictionary*)_inputDict {
    BOOL isSuccess = NO;
    CBLDocument* doc = [[CouchBaseLiteLib sharedCouchBaseLite].database untitledDocument];
    NSError* error;
    if (![doc putProperties:_inputDict error: &error]) {
        //add failed
    }
    else {
        isSuccess = YES;
    }
    
    return isSuccess;
}

+ (NSMutableArray*) listInspection {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listInspection"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:InspectionDoc])
                emit(doc, nil);
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    
    for (CBLQueryRow* row in query.rows) {
        [tmpArray addObject:row.document.properties];
    }
    return tmpArray;
}

+ (NSMutableArray*) listInspectionFrom:(int)from numberRow:(int)count {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    double timeInterval = [[userDefaults objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
    NSTimeInterval timeIntervalLimited = [[[NSDate date] dateByAddingTimeInterval:-timeInterval] timeIntervalSince1970];
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    
    CBLView* view = [_database viewNamed: @"listInspectionsAndMaintenances"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id maintenanceTypeId = [doc objectForKey:@"maintenanceTypeId"] == nil ? @"" : [doc objectForKey:@"maintenanceTypeId"];
            id dateUpdated = doc[@"dateUpdated"];
            id itemId = doc[@"itemId"];
            id table  = doc[@"Table"];
            BOOL workComplete = [[doc objectForKey:@"workComplete"] boolValue];
            if (table && maintenanceTypeId && itemId && !workComplete)
                emit(@[table,maintenanceTypeId,dateUpdated], doc);
            
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.limit = count;
    query.skip  = from;
    query.descending = YES;
    query.startKey = @[InspectionDoc,@{},@{}];
    query.endKey   = @[InspectionDoc];
    
    for (CBLQueryRow* row in query.rows) {
        double dateUpdated = [[row.document propertyForKey:@"dateUpdated"] doubleValue];
        if (dateUpdated >= timeIntervalLimited)
            [tmpArray addObject:row.document.properties];
    }
    
    return tmpArray;
}

+ (NSMutableArray*) listInspectionByContractor:(NSString*)_contractorId from:(int)from numberRow:(int)count {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    double timeInterval = [[userDefaults objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
    NSTimeInterval timeIntervalLimited = [[[NSDate date] dateByAddingTimeInterval:-timeInterval] timeIntervalSince1970];
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
   
    CBLView* view = [_database viewNamed: @"listInspectionsAndMaintenances"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id maintenanceTypeId = [doc objectForKey:@"maintenanceTypeId"] == nil ? @"" : [doc objectForKey:@"maintenanceTypeId"];
            id dateUpdated = doc[@"dateUpdated"];
            id itemId = doc[@"itemId"];
            id table  = doc[@"Table"];
            BOOL workComplete = [[doc objectForKey:@"workComplete"] boolValue];
            if (table && maintenanceTypeId && itemId && !workComplete)
                emit(@[table,maintenanceTypeId,dateUpdated], doc);
            
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
//    query.limit = count;
//    query.skip  = from;
    query.descending = YES;
    query.startKey = @[InspectionDoc,@{},@{}];
    query.endKey   = @[InspectionDoc];
    
    for (CBLQueryRow* row in query.rows) {
        NSString *scheduleId = [row.document propertyForKey:@"scheduleId"];
        CBLDocument *scheduleDoc = [CouchBaseLiteLib getDocumentById:scheduleId];
        NSString *contractorId = [[scheduleDoc propertyForKey:@"personInCharge"] objectForKey:@"_id"];
        NSString *userId = [row.document propertyForKey:@"userId"];
        double dateUpdated = [[row.document propertyForKey:@"dateUpdated"] doubleValue];

        if (([contractorId isEqualToString:_contractorId] || [userId isEqualToString:_contractorId]) && dateUpdated >= timeIntervalLimited)
            [tmpArray addObject:row.document.properties];
    }
    
    //split page
    NSMutableArray *arrayResult = [NSMutableArray arrayWithCapacity:1];
    for (int i=from;i < from + count && i < [tmpArray count];i++) {
        [arrayResult addObject:[tmpArray objectAtIndex:i]];
    }
    
    return arrayResult;
}

+ (NSMutableArray*) listInspectionByItem:(NSString*)_itemId {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    double timeInterval = [[userDefaults objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
    NSTimeInterval timeIntervalLimited = [[[NSDate date] dateByAddingTimeInterval:-timeInterval] timeIntervalSince1970];
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listInspectionByItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:InspectionDoc]) {
                id itemId = doc[@"itemId"];
                BOOL workComplete = [[doc objectForKey:@"workComplete"] boolValue];
                if (itemId && workComplete)
                    emit(CBLTextKey(itemId), doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",_itemId];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    
    for (CBLQueryRow* row in query.rows) {
        double dateUpdated = [[row.document propertyForKey:@"dateUpdated"] doubleValue];
        if (dateUpdated >= timeIntervalLimited)
            [tmpArray addObject:row.document.properties];
    }
    
    return tmpArray;
}

+ (NSMutableArray*) listMaintenance {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listMaintenance"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:MaintenanceDoc])
                emit(doc, nil);
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    
    for (CBLQueryRow* row in query.rows) {
        [tmpArray addObject:row.document.properties];
    }
    return tmpArray;
}

+ (NSMutableArray*) listMaintenanceFrom:(int)from numberRow:(int)count {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listMaintenancesAndOrder"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:MaintenanceDoc]) {
                id dateUpdated = doc[@"dateUpdated"];
                emit(dateUpdated, nil);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.limit = count;
    query.skip  = from;
    query.descending = YES;
    
    for (CBLQueryRow* row in query.rows) {
        [tmpArray addObject:row.document.properties];
    }
    return tmpArray;
}

+ (NSMutableArray*) listMaintenanceByItem:(NSString*)_itemId {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    double timeInterval = [[userDefaults objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
    NSTimeInterval timeIntervalLimited = [[[NSDate date] dateByAddingTimeInterval:-timeInterval] timeIntervalSince1970];
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listMaintenanceByItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:MaintenanceDoc]) {
                id itemId = doc[@"itemId"];
                
                if (itemId)
                    emit(CBLTextKey(itemId), doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",_itemId];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    
    for (CBLQueryRow* row in query.rows) {
        double dateUpdated = [[row.document propertyForKey:@"dateUpdated"] doubleValue];
        if (dateUpdated >= timeIntervalLimited)
            [tmpArray addObject:row.document.properties];
    }
    return tmpArray;
}

+ (NSMutableArray*) listMaintenanceAndInspectionByItem:(NSString*)_itemId from:(int)from numberRow:(int)count {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    double timeInterval = [[userDefaults objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
    NSTimeInterval timeIntervalLimited = [[[NSDate date] dateByAddingTimeInterval:-timeInterval] timeIntervalSince1970];
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    CBLView* view = [_database viewNamed: @"listMaintenanceAndInspectionByItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:MaintenanceDoc] || [doc[@"Table"] isEqualToString:InspectionDoc]) {
                id item = [doc objectForKey:@"itemId"];
                id dateUpdated = [doc objectForKey:@"dateUpdated"];
                id workComplete = [doc objectForKey:@"workComplete"];
                if (item && workComplete)
                    emit(@[item,workComplete,dateUpdated],doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.limit = count;
    query.skip  = from;
    query.startKey = @[_itemId,@YES,@{}];
    query.endKey   = @[_itemId,@YES];
    query.descending = YES;
    
    for (CBLQueryRow* row in query.rows) {
        NSLog(@"row = %@",row.document.properties);
        double dateUpdated = [[row.document propertyForKey:@"dateUpdated"] doubleValue];
        if (dateUpdated >= timeIntervalLimited)
            [tmpArray addObject:row.document.properties];
    }
    
    return tmpArray;
}

+ (NSMutableArray*) listMaintenanceByType:(int)_maintenanceTypeId from:(int)from numberRow:(int)count {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    double timeInterval = [[userDefaults objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
    NSTimeInterval timeIntervalLimited = [[[NSDate date] dateByAddingTimeInterval:-timeInterval] timeIntervalSince1970];
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    
    CBLView* view = [_database viewNamed: @"listInspectionsAndMaintenances"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id maintenanceTypeId = [doc objectForKey:@"maintenanceTypeId"] == nil ? @"" : [doc objectForKey:@"maintenanceTypeId"];
            id dateUpdated = doc[@"dateUpdated"];
            id itemId = doc[@"itemId"];
            id table  = doc[@"Table"];
            BOOL workComplete = [[doc objectForKey:@"workComplete"] boolValue];
            if (table && maintenanceTypeId && itemId && !workComplete)
                emit(@[table,maintenanceTypeId,dateUpdated], doc);
            
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    
    CBLQuery *query = [view query];
    if (_maintenanceTypeId != 0) {
        query.startKey = @[MaintenanceDoc,[NSString stringWithFormat:@"%d",_maintenanceTypeId],@{}];
        query.endKey   = @[MaintenanceDoc,[NSString stringWithFormat:@"%d",_maintenanceTypeId]];
    }
    else {
        query.startKey = @[MaintenanceDoc,@{},@{}];
        query.endKey   = @[MaintenanceDoc];
    }
    query.limit = count;
    query.skip  = from;
    query.descending = YES;
    for (CBLQueryRow* row in query.rows) {
        double dateUpdated = [[row.document propertyForKey:@"dateUpdated"] doubleValue];
        if (dateUpdated >= timeIntervalLimited)
            [tmpArray addObject:row.document.properties];
    }
    
    return tmpArray;
}

+ (NSMutableArray*) listMaintenanceByType:(int)_maintenanceTypeId contractor:(NSString*)_contractorId from:(int)from numberRow:(int)count {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    double timeInterval = [[userDefaults objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
    NSTimeInterval timeIntervalLimited = [[[NSDate date] dateByAddingTimeInterval:-timeInterval] timeIntervalSince1970];
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    
    CBLView* view = [_database viewNamed: @"listInspectionsAndMaintenances"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id maintenanceTypeId = [doc objectForKey:@"maintenanceTypeId"] == nil ? @"" : [doc objectForKey:@"maintenanceTypeId"];
            id dateUpdated = doc[@"dateUpdated"];
            id itemId = doc[@"itemId"];
            id table  = doc[@"Table"];
            BOOL workComplete = [[doc objectForKey:@"workComplete"] boolValue];
            if (table && maintenanceTypeId && itemId && !workComplete)
                emit(@[table,maintenanceTypeId,dateUpdated], doc);
            
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    
    CBLQuery *query = [view query];
    if (_maintenanceTypeId != 0) {
        query.startKey = @[MaintenanceDoc,[NSString stringWithFormat:@"%d",_maintenanceTypeId],@{}];
        query.endKey   = @[MaintenanceDoc,[NSString stringWithFormat:@"%d",_maintenanceTypeId]];
    }
    else {
        query.startKey = @[MaintenanceDoc,@{},@{}];
        query.endKey   = @[MaintenanceDoc];
    }
//    query.limit = count;
//    query.skip  = from;
    query.descending = YES;
    
    for (CBLQueryRow* row in query.rows) {
        NSString *scheduleId = [row.document propertyForKey:@"scheduleId"];
        CBLDocument *scheduleDoc = [CouchBaseLiteLib getDocumentById:scheduleId];
        NSString *contractorId = [[scheduleDoc propertyForKey:@"personInCharge"] objectForKey:@"_id"];
        NSString *userId = [row.document propertyForKey:@"userId"];
        double dateUpdated = [[row.document propertyForKey:@"dateUpdated"] doubleValue];
        if (([contractorId isEqualToString:_contractorId] || [userId isEqualToString:_contractorId]) && dateUpdated >= timeIntervalLimited)
            [tmpArray addObject:row.document.properties];
    }
    
    //split page
    NSMutableArray *arrayResult = [NSMutableArray arrayWithCapacity:1];
    for (int i=from;i < from + count && i < [tmpArray count];i++) {
        [arrayResult addObject:[tmpArray objectAtIndex:i]];
    }

    return arrayResult;
}

#pragma mark Schedule
+ (int) countUnreadSchedulingByItem:(NSMutableDictionary*)_itemDict {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    double timeInterval = [[userDefaults objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
    NSTimeInterval timeIntervalLimited = [[[NSDate date] dateByAddingTimeInterval:-timeInterval] timeIntervalSince1970];
    
    NSString *itemId = [_itemDict objectForKey:@"_id"];
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"listSchedulesOfItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:kScheduleDocType]) {
                id dateUpdated = [doc objectForKey:@"dateUpdated"];
                id itemId = [doc objectForKey:@"itemId"];
                if (itemId)
                    emit(@[itemId,dateUpdated],doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.startKey  = @[itemId,@{}];
    query.endKey    = @[itemId];
    query.descending = YES;
    
    //filter document by was read
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        int wasRead = [[row.document propertyForKey:@"wasRead"] intValue];
        double dateUpdated = [[row.document propertyForKey:@"dateUpdated"] doubleValue];
        if (!wasRead && dateUpdated >= timeIntervalLimited)
            [tmpArray addObject:row.document.properties];
    }
    
    return [tmpArray count];
}

+ (NSMutableArray*) listScheduleByItem:(NSMutableDictionary*)_itemDict from:(int)from numberRow:(int)count {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    double timeInterval = [[userDefaults objectForKey:TIME_DURATION_DB_SERVER] doubleValue];
    NSTimeInterval timeIntervalLimited = [[[NSDate date] dateByAddingTimeInterval:-timeInterval] timeIntervalSince1970];
    
    NSString *itemId = [_itemDict objectForKey:@"_id"];
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"listSchedulesOfItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:kScheduleDocType]) {
                id dateUpdated = [doc objectForKey:@"dateUpdated"];
                id itemId = [doc objectForKey:@"itemId"];
                if (itemId)
                    emit(@[itemId,dateUpdated],doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.startKey  = @[itemId,@{}];
    query.endKey    = @[itemId];
    query.descending = YES;
    query.limit = count;
    query.skip  = from;
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        double dateUpdated = [[row.document propertyForKey:@"dateUpdated"] doubleValue];
        if (dateUpdated >= timeIntervalLimited)
            [tmpArray addObject:row.document.properties];
    }
    
    return tmpArray;
}

#pragma mark Document Attachment
+ (NSMutableArray*) listDocumentAttachmentByItem:(NSString*)_itemId {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    /*
    CBLView* view = [_database viewNamed: @"listDocumentsAttachmentByItem"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:DocumentAttachment]) {
                id _itemId = doc[@"itemId"];
                emit(CBLTextKey(_itemId), doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",_itemId];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    */
    
    CBLView* view = [_database viewNamed: @"DocumentsAndAttachments"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id _itemId = doc[@"itemId"] == nil ? @"" : doc[@"itemId"];
            id maintenanceId = [doc objectForKey:@"maintenanceId"] == nil ? @"" : doc[@"maintenanceId"];
            id documentUrl = doc[@"imageUrl"] == nil ? @"" : doc[@"imageUrl"];
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table && _itemId && maintenanceId && documentUrl)
                emit(@[table,_itemId,maintenanceId,documentUrl], doc);
            
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.startKey = @[DocumentAttachment,_itemId];
    query.endKey   = @[DocumentAttachment,_itemId,@{},@{}];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        [tmpArray addObject:row.document.properties];
    }
    return tmpArray;
}

+ (NSMutableArray*) listItemsByDocument:(NSString*)_documentLink {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    /*
    CBLView* view = [_database viewNamed: @"listItemsByDocument"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:DocumentAttachment]) {
                id documentUrl = doc[@"imageUrl"];
                emit(CBLTextKey(documentUrl), doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",_documentLink];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
     */
    CBLView* view = [_database viewNamed: @"DocumentsAndAttachments"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id _itemId = doc[@"itemId"] == nil ? @"" : doc[@"itemId"];
            id maintenanceId = [doc objectForKey:@"maintenanceId"] == nil ? @"" : doc[@"maintenanceId"];
            id documentUrl = doc[@"imageUrl"] == nil ? @"" : doc[@"imageUrl"];
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table && _itemId && maintenanceId && documentUrl)
                emit(@[table,_itemId,maintenanceId,documentUrl], doc);
            
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.startKey = @[DocumentAttachment,@{},@{},_documentLink];
    query.endKey   = @[DocumentAttachment,@{},@{},_documentLink];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        [tmpArray addObject:row.document.properties];
    }
    return tmpArray;
}

+ (NSMutableArray*) listItemsByDocument:(NSString*)_documentLink from:(int)from numberRow:(int)count {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    
    CBLView* view = [_database viewNamed: @"listItemsByDocument"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:DocumentAttachment]) {
                id documentUrl = doc[@"imageUrl"];
                emit(CBLTextKey(documentUrl), doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",_documentLink];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    query.limit = count;
    query.skip  = from;
    query.descending = NO;
    
    /*
    CBLView* view = [_database viewNamed: @"DocumentsAndAttachments"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id _itemId = doc[@"itemId"] == nil ? @"" : doc[@"itemId"];
            id maintenanceId = [doc objectForKey:@"maintenanceId"] == nil ? @"" : doc[@"maintenanceId"];
            id documentUrl = doc[@"imageUrl"] == nil ? @"" : doc[@"imageUrl"];
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table && _itemId && maintenanceId && documentUrl)
                emit(@[table,_itemId,maintenanceId,documentUrl], doc);
            
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.startKey = @[DocumentAttachment,@{},@{},_documentLink];
    query.endKey   = @[DocumentAttachment,@{},@{},_documentLink];
    query.limit = count;
    query.skip  = from;
    query.descending = NO;
     */
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        [tmpArray addObject:row.document.properties];
    }
    return tmpArray;
}

+ (BOOL) checkExistedItemByDocument:(NSString*)_itemId documentLink:(NSString*)_documentLink {
    BOOL isExisted = NO;
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    
    CBLView* view = [_database viewNamed: @"listItemsByDocument"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:DocumentAttachment]) {
                id documentUrl = doc[@"imageUrl"];
                emit(CBLTextKey(documentUrl), doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",_documentLink];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
     
    /*
    CBLView* view = [_database viewNamed: @"DocumentsAndAttachments"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id _itemId = doc[@"itemId"] == nil ? @"" : doc[@"itemId"];
            id maintenanceId = [doc objectForKey:@"maintenanceId"] == nil ? @"" : doc[@"maintenanceId"];
            id documentUrl = doc[@"imageUrl"] == nil ? @"" : doc[@"imageUrl"];
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table && _itemId && maintenanceId && documentUrl)
                emit(@[table,_itemId,maintenanceId,documentUrl], doc);
            
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.startKey = @[DocumentAttachment,@{},@{},_documentLink];
    query.endKey   = @[DocumentAttachment,@{},@{},_documentLink];
    */
    for (CBLQueryRow* row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        NSString *itemId = [dict objectForKey:@"itemId"];
        if ([itemId isEqualToString:_itemId]){
            isExisted = YES;
            break;
        }
    }
    
    return isExisted;
}

#pragma mark Filter data

+ (NSMutableArray*) listService {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"listServices"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table)
                emit(table, doc);
        }) reduceBlock: nil version: @"1.2"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[@"Service"];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        //check another key for status
        NSString *statusStr = [NSString stringWithFormat:@"%@",[dict objectForKey:@"status"]];
        if ([statusStr isEqualToString:@"1"] || [statusStr isEqualToString:@"active"] || [statusStr isEqualToString:@"Active"]) {
            NSString *name = [dict objectForKey:@"serviceName"];
            @try {
                [dict setObject:[dict objectForKey:@"_id"] forKey:@"index"];
                [dict setObject:name forKey:@"filterName"];
                [dict setObject:[NSString stringWithFormat:@"%d",filter_service] forKey:@"filterType"];
                [tmpArray addObject:dict];
            }
            @catch (NSException *e) {
                NSLog(@"%@",e);
                continue;
            }
        }
    }
    return tmpArray;
}

+ (NSMutableArray*) listCampByService:(NSString*)_serviceId {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
//    CBLView* view = [_database viewNamed: @"listCampByService"];
//    if (!view.mapBlock) {
//        // Register the map function, the first time we access the view:
//        [view setMapBlock: MAPBLOCK({
//            if ([doc[@"Table"] isEqualToString:@"Service"]) {
//                id _id = doc[@"_id"];
//                emit(CBLTextKey(_id), doc);
//            }
//        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
//    }
//    CBLQuery *query = [view query];
//    query.fullTextQuery = [NSString stringWithFormat:@"%@",_serviceId];
//    query.fullTextSnippets = YES;   // enables snippets; see next example
//    query.fullTextRanking = YES;
    
    CBLView* view = [_database viewNamed: @"listServices"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table)
                emit(table, doc);
        }) reduceBlock: nil version: @"1.2"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[@"Service"];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        if ([[row.document propertyForKey:@"_id"] isEqualToString:_serviceId]) {
            NSMutableArray *campArray = [row.document.properties objectForKey:@"camp"];
            for (int i=0;i < [campArray count];i++) {
                NSMutableDictionary *campDict = [[campArray objectAtIndex:i] mutableCopy];
                NSString *statusStr = [NSString stringWithFormat:@"%@",[campDict objectForKey:@"status"]];
                if ([statusStr isEqualToString:@"1"] || [statusStr isEqualToString:@"active"] || [statusStr isEqualToString:@"Active"]) {
                    NSString *name = [campDict objectForKey:@"campName"];
                    @try {
                        [campDict setObject:[campDict objectForKey:@"idCamp"] forKey:@"index"];
                        [campDict setObject:name forKey:@"filterName"];
                        [campDict setObject:[NSString stringWithFormat:@"%d",filter_camp] forKey:@"filterType"];
                        [tmpArray addObject:campDict];
                    }
                    @catch (NSException *e) {
                        NSLog(@"%@",e);
                    }
                }
            }
            break;
        }
    }
    return tmpArray;
}

+ (NSMutableArray*) listUnitByService:(NSString*)_serviceId andCamp:(NSString*)_campId {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
//    CBLView* view = [_database viewNamed: @"listCampByService"];
//    if (!view.mapBlock) {
//        // Register the map function, the first time we access the view:
//        [view setMapBlock: MAPBLOCK({
//            if ([doc[@"Table"] isEqualToString:@"Service"]) {
//                id _id = doc[@"_id"];
//                emit(CBLTextKey(_id), doc);
//            }
//        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
//    }
//    CBLQuery *query = [view query];
//    query.fullTextQuery = [NSString stringWithFormat:@"%@",_serviceId];
//    query.fullTextSnippets = YES;   // enables snippets; see next example
//    query.fullTextRanking = YES;
    
    CBLView* view = [_database viewNamed: @"listServices"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table)
                emit(table, doc);
        }) reduceBlock: nil version: @"1.2"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[@"Service"];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        if ([[row.document propertyForKey:@"_id"] isEqualToString:_serviceId]) {
            NSMutableArray *campArray = [row.document.properties objectForKey:@"camp"];
            for (int i=0;i < [campArray count];i++) {
                NSMutableDictionary *campDict = [[campArray objectAtIndex:i] mutableCopy];
                NSString *campId = [campDict objectForKey:@"idCamp"];
                NSString *statusStr = [NSString stringWithFormat:@"%@",[campDict objectForKey:@"status"]];
                if ([campId isEqualToString:_campId] && ([statusStr isEqualToString:@"1"] || [statusStr isEqualToString:@"active"] || [statusStr isEqualToString:@"Active"])) {
                    //get unit array and check status of unit
                    NSMutableArray *unitArray = [campDict objectForKey:@"unit"];
                    for (int j=0;j < [unitArray count];j++) {
                        NSMutableDictionary *unitDict = [[unitArray objectAtIndex:j] mutableCopy];
                        
                        statusStr = [NSString stringWithFormat:@"%@",[unitDict objectForKey:@"status"]];
                        if ([statusStr isEqualToString:@"1"] || [statusStr isEqualToString:@"active"] || [statusStr isEqualToString:@"Active"]) {
                            @try {
                                NSString *name = [unitDict objectForKey:@"unitName"];
                                [unitDict setObject:[unitDict objectForKey:@"idUnit"] forKey:@"index"];
                                [unitDict setObject:name forKey:@"filterName"];
                                [unitDict setObject:[NSString stringWithFormat:@"%d",filter_unit] forKey:@"filterType"];
                                [tmpArray addObject:unitDict];
                            }
                            @catch (NSException *e) {
                                NSLog(@"%@",e);
                                continue;
                            }
                        }
                    }
                }
            }
            break;
        }
    }
    return tmpArray;
}

+ (NSMutableArray*) listBuildingByUnit:(NSString*)_unitId from:(int)from numberRow:(int)count {
    if (_unitId == nil)
        return nil;
    
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"listBuildingsByUnit"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:@"Building"]) {
                id unitId = doc[@"idUnit"];
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                id isOther = [doc objectForKey:@"isOther"];
                
                if (status && unitId && isOther)
                    emit(@[unitId,isOther],doc);
            }
        }) reduceBlock: nil version: @"1.1"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
//    query.fullTextQuery = [NSString stringWithFormat:@"%@",_unitId];
//    query.fullTextSnippets = YES;   // enables snippets; see next example
//    query.fullTextRanking = YES;
    query.skip  = from;
    query.limit = count;
    query.descending = YES;
    
    query.keys = @[@[_unitId,@0]];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        NSString *buildingName = [dict objectForKey:@"buildingName"];
        @try {
            [dict setObject:[dict objectForKey:@"_id"] forKey:@"index"];
            [dict setObject:buildingName forKey:@"filterName"];
            [dict setObject:[NSString stringWithFormat:@"%d",filter_building] forKey:@"filterType"];
            [tmpArray addObject:dict];
        }
        @catch (NSException *exception) {
            NSLog(@"listBuilding = %@",exception);
            continue;
        }
    }
    return tmpArray;
}

+ (NSMutableArray*) listOtherBuildingByUnit:(NSString*)_unitId from:(int)from numberRow:(int)count {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"listBuildingsByUnit"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:@"Building"]) {
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                id unitId = doc[@"idUnit"];
                
                id isOther = [doc objectForKey:@"isOther"];
                
                if (status && unitId && isOther)
                    emit(@[unitId,isOther],doc);
            }
        }) reduceBlock: nil version: @"1.1"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.skip  = from;
    query.limit = count;
    query.descending = YES;
    
    query.keys = @[@[_unitId,@1]];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        NSString *buildingName = [dict objectForKey:@"buildingName"];
        @try {
            [dict setObject:[dict objectForKey:@"_id"] forKey:@"index"];
            [dict setObject:buildingName forKey:@"filterName"];
            [dict setObject:[NSString stringWithFormat:@"%d",filter_building] forKey:@"filterType"];
            [tmpArray addObject:dict];
        }
        @catch (NSException *exception) {
            NSLog(@"listBuilding = %@",exception);
            continue;
        }
    }
    return tmpArray;
}

+ (NSMutableArray*) listFloorsByBuilding:(NSString*)_buildingId {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"listFloorsByBuilding"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:@"Building"]) {
                id _id = doc[@"_id"];
                emit(CBLTextKey(_id), doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",_buildingId];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        NSMutableArray *floorArray = [row.document.properties objectForKey:@"floors"];
        for (int i=0;i < [floorArray count];i++) {
            NSMutableDictionary *floorDict = [[floorArray objectAtIndex:i] mutableCopy];
            BOOL status = [[floorDict objectForKey:@"status"] boolValue];
            if (status) {
                NSString *name = [floorDict objectForKey:@"name"];
                [floorDict setObject:[floorDict objectForKey:@"id"] forKey:@"index"];
                [floorDict setObject:name forKey:@"filterName"];
                [floorDict setObject:[NSString stringWithFormat:@"%d",filter_floor] forKey:@"filterType"];
                [tmpArray addObject:floorDict];
            }
        }
    }
    return tmpArray;
}

+ (NSMutableArray*) listSystemByFilter:(NSMutableDictionary*)_filterValueDict {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"listSystemByFilter"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:@"System"]) {
                id systemName = doc[@"systemName"];
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                
                id service = [doc objectForKey:@"service"];
                id camp    = [doc objectForKey:@"camp"];
                id unit    = [doc objectForKey:@"unit"];
                id building = [doc objectForKey:@"building"];
                id floor    = [doc objectForKey:@"floor"];
                id room     = [doc objectForKey:@"room"];
                
                if (status && systemName && service && camp && unit && building && floor && room) {
                    emit(@[service,camp,unit,building,floor,room],nil);
                }
                
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.descending = YES;
    
    NSString *service = [_filterValueDict objectForKey:@"service"];
    NSString *camp    = [_filterValueDict objectForKey:@"camp"];
    NSString *unit    = [_filterValueDict objectForKey:@"unit"];
    NSString *building = [_filterValueDict objectForKey:@"building"];
    NSString *floor    = [_filterValueDict objectForKey:@"floor"];
    NSString *room     = [_filterValueDict objectForKey:@"room"];
    
    if (_filterValueDict != nil) {
        if ([floor isEqualToString:@"0"]) {
            query.startKey = @[service,camp,unit,building,@{},@{}];
            query.endKey   = @[service,camp,unit,building];
        }
        else {
            query.startKey = @[service,camp,unit,building,floor,room];
            query.endKey   = @[service,camp,unit,building,floor,room];
        }
    }
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        NSString *name = [dict objectForKey:@"systemName"];
        [dict setObject:[dict objectForKey:@"_id"] forKey:@"index"];
        [dict setObject:name forKey:@"filterName"];
        [dict setObject:[NSString stringWithFormat:@"%d",filter_system] forKey:@"filterType"];
        [tmpArray addObject:dict];
    }
    return tmpArray;
}

+ (NSMutableArray*) listDescriptionBySystem:(NSString*)_systemName {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"listServices"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table)
                emit(table, doc);
        }) reduceBlock: nil version: @"1.2"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[@"Description"];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        BOOL status = [[dict objectForKey:@"status"] boolValue];
        NSString *system = [dict objectForKey:@"system"];
        if (status && [system isEqualToString:_systemName]) {
            NSString *name = [dict objectForKey:@"descriptionName"];
            [dict setObject:[dict objectForKey:@"_id"] forKey:@"index"];
            [dict setObject:name forKey:@"filterName"];
            [dict setObject:[NSString stringWithFormat:@"%d",filter_description] forKey:@"filterType"];
            [tmpArray addObject:dict];
        }
    }
    return tmpArray;
}

+ (NSMutableDictionary*) getServiceByName:(NSString*)_serviceName {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
//    CBLView* view = [_database viewNamed: @"getServiceByName"];
//    if (!view.mapBlock) {
//        // Register the map function, the first time we access the view:
//        [view setMapBlock: MAPBLOCK({
//            if ([doc[@"Table"] isEqualToString:@"Service"]) {
//                id serviceName = [doc objectForKey:@"serviceName"];
//                emit(CBLTextKey(serviceName), nil);
//            }
//        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
//    }
//    CBLQuery *query = [view query];
//    query.fullTextQuery = [NSString stringWithFormat:@"%@",_serviceName];
//    query.fullTextSnippets = YES;   // enables snippets; see next example
//    query.fullTextRanking = YES;
    
    CBLView* view = [_database viewNamed: @"listServices"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table)
                emit(table, doc);
        }) reduceBlock: nil version: @"1.2"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[@"Service"];
    
    NSMutableDictionary *tmpDict;
    for (CBLQueryRow* row in query.rows) {
        if ([[row.document propertyForKey:@"serviceName"] isEqualToString:_serviceName]) {
            tmpDict = [row.document.properties mutableCopy];
            break;
        }
    }
    return tmpDict;
}

+ (NSMutableDictionary*) getCampByService:(NSString*)_serviceId andCampName:(NSString*)_campName {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
//    CBLView* view = [_database viewNamed: @"listCampByService"];
//    if (!view.mapBlock) {
//        // Register the map function, the first time we access the view:
//        [view setMapBlock: MAPBLOCK({
//            if ([doc[@"Table"] isEqualToString:@"Service"]) {
//                id _id = doc[@"_id"];
//                emit(CBLTextKey(_id), doc);
//            }
//        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
//    }
//    CBLQuery *query = [view query];
//    query.fullTextQuery = [NSString stringWithFormat:@"%@",_serviceId];
//    query.fullTextSnippets = YES;   // enables snippets; see next example
//    query.fullTextRanking = YES;
    CBLView* view = [_database viewNamed: @"listServices"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table)
                emit(table, doc);
        }) reduceBlock: nil version: @"1.2"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[@"Service"];
    
    NSMutableDictionary *tmpDict;
    for (CBLQueryRow* row in query.rows) {
        if ([[row.document propertyForKey:@"_id"] isEqualToString:_serviceId]) {
            NSMutableArray *campArray = [row.document.properties objectForKey:@"camp"];
            for (int i=0;i < [campArray count];i++) {
                NSMutableDictionary *campDict = [[campArray objectAtIndex:i] mutableCopy];
                NSString *campName = [campDict objectForKey:@"campName"];
                if ([campName isEqualToString:_campName]) {
                    tmpDict = campDict;
                }
            }
            break;
        }
    }
    return tmpDict;
}

+ (NSMutableDictionary*) getUnitByService:(NSString*)_serviceId andCamp:(NSString*)_campId andUnitName:(NSString*)_unitName {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
//    CBLView* view = [_database viewNamed: @"listCampByService"];
//    if (!view.mapBlock) {
//        // Register the map function, the first time we access the view:
//        [view setMapBlock: MAPBLOCK({
//            if ([doc[@"Table"] isEqualToString:@"Service"]) {
//                id _id = doc[@"_id"];
//                emit(CBLTextKey(_id), doc);
//            }
//        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
//    }
//    CBLQuery *query = [view query];
//    query.fullTextQuery = [NSString stringWithFormat:@"%@",_serviceId];
//    query.fullTextSnippets = YES;   // enables snippets; see next example
//    query.fullTextRanking = YES;
    
    CBLView* view = [_database viewNamed: @"listServices"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            id table = doc[@"Table"] == nil ? @"" : doc[@"Table"];
            if (table)
                emit(table, doc);
        }) reduceBlock: nil version: @"1.2"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[@"Service"];
    
    NSMutableDictionary *tmpDict;
    for (CBLQueryRow* row in query.rows) {
        if ([[row.document propertyForKey:@"_id"] isEqualToString:_serviceId]) {
            NSMutableArray *campArray = [row.document.properties objectForKey:@"camp"];
            for (int i=0;i < [campArray count];i++) {
                NSMutableDictionary *campDict = [[campArray objectAtIndex:i] mutableCopy];
                NSString *campId = [campDict objectForKey:@"idCamp"];
                if ([campId isEqualToString:_campId]) {
                    //get unit array and check status of unit
                    NSMutableArray *unitArray = [campDict objectForKey:@"unit"];
                    for (int j=0;j < [unitArray count];j++) {
                        NSMutableDictionary *unitDict = [[unitArray objectAtIndex:j] mutableCopy];
                        NSString *unitName = [unitDict objectForKey:@"unitName"];
                        if ([unitName isEqualToString:_unitName]) {
                            tmpDict = unitDict;
                        }
                    }
                }
            }
            break;
        }
    }
    return tmpDict;
}

+ (NSMutableDictionary*) getBuildingByName:(NSString*)_buildingName {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"getBuildingByName"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:@"Building"]) {
                id name = doc[@"buildingName"];
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                BOOL isOther = [[doc objectForKey:@"isOther"] boolValue];
                if (status && name && !isOther)
                    emit(CBLTextKey(name),doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",_buildingName];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    query.descending = YES;
    
    NSMutableDictionary *tmpDict;
    for (CBLQueryRow *row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        NSString *buildingName = [dict objectForKey:@"buildingName"];
        if ([buildingName isEqualToString:_buildingName]) {
            tmpDict = dict;
        }
    }
    return tmpDict;
}

+ (NSMutableDictionary*) getFloorByBuilding:(NSString*)_buildingName andFloorName:(NSString*)_floorName {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"getBuildingByName"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:@"Building"]) {
                id name = doc[@"buildingName"];
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                BOOL isOther = [[doc objectForKey:@"isOther"] boolValue];
                if (status && name && !isOther)
                    emit(CBLTextKey(name),doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.fullTextQuery = [NSString stringWithFormat:@"%@",_buildingName];
    query.fullTextSnippets = YES;   // enables snippets; see next example
    query.fullTextRanking = YES;
    query.descending = YES;
    
    NSMutableDictionary *tmpDict;
    for (CBLQueryRow *row in query.rows) {
        NSMutableArray *floorArray = [row.document.properties objectForKey:@"floors"];
        for (int i=0;i < [floorArray count];i++) {
            NSMutableDictionary *floorDict = [[floorArray objectAtIndex:i] mutableCopy];
            NSString *name = [floorDict objectForKey:@"name"];
            if ([name isEqualToString:_floorName]) {
                tmpDict = floorDict;
            }
        }
    }
    return tmpDict;
}

#pragma mark Maintenance Document
+ (NSMutableArray*) listAttachmentByMaintenance:(NSString*)_maintenanceId andType:(int)_maintenanceType {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    
    CBLView* view = [_database viewNamed: @"listAttachmentByMaintenance"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:MaintenanceAttachment]) {
                id maintenanceId = [doc objectForKey:@"maintenanceId"];
                if (maintenanceId)
                    emit(maintenanceId,doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[_maintenanceId];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        int maintenanceType = [[dict objectForKey:@"attachDocumentType"] intValue];
        if (maintenanceType == _maintenanceType) {
            [tmpArray addObject:dict];
        }
    }
    return tmpArray;
}

#pragma mark USER
+ (NSMutableArray*) listUserByRole:(NSString*)_roleName {
    CBLDatabase *_database = [CouchBaseLiteLib sharedCouchBaseLite].database;
    CBLView* view = [_database viewNamed: @"listUserByRole"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if ([doc[@"Table"] isEqualToString:kUserDocType]) {
//                id email = [doc objectForKey:@"email"];
                id name  = [doc objectForKey:@"name"];
                id role  = [doc objectForKey:@"role"];
                BOOL status = [[doc objectForKey:@"status"] boolValue];
                if (name && role && status == YES)
                    emit(role,doc);
            }
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    query.keys = @[_roleName];
    
    NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow* row in query.rows) {
        NSMutableDictionary *dict = [row.document.properties mutableCopy];
        [tmpArray addObject:dict];
    }
    return tmpArray;
}

+ (NSMutableArray *) listUserLiasonAndContact:(int)indexFrom numberPage:(int)count {
    CBLView* view = [[CouchBaseLiteLib sharedCouchBaseLite].database viewNamed: @"listsNewContact"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if (([doc[@"Table"] isEqualToString:kLiaisonDocType] && doc[@"personInCharge"] && ![doc[@"personInCharge"] isEqualToString:@""])|| ([doc[@"Table"] isEqualToString:kUserDocType] && [[doc objectForKey:@"status"] intValue] == 1))
                emit(doc, nil);
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow *row in query.rows) {
        if ([[row.document propertyForKey:@"Table"] isEqualToString:kUserDocType]) {
            NSString *role = [[row.document propertyForKey:@"role"] lowercaseString];
            if ([role isEqualToString:@"liaison"])
                [array addObject:[row.document.properties mutableCopy]];
        }
        else {
            //những user thuộc Contact Mgmt co role liaison
            NSString *role   = [[row.document propertyForKey:@"typeLiaison"] lowercaseString];
            if ([role isEqualToString:@"liaison"])
                [array addObject:[row.document.properties mutableCopy]];
        }
    }
    [array sortUsingComparator:^(NSMutableDictionary *obj1, NSMutableDictionary *obj2){
        NSString *name1;
        if ([[obj1 objectForKey:@"Table"] isEqualToString:kUserDocType])
            name1 = [obj1 objectForKey:@"name"];
        else
            name1 = [obj1 objectForKey:@"personInCharge"];
        
        NSString *name2;
        if ([[obj2 objectForKey:@"Table"] isEqualToString:kUserDocType])
            name2 = [obj2 objectForKey:@"name"];
        else
            name2 = [obj2 objectForKey:@"personInCharge"];
        
        return [name1 compare:name2 options:NSCaseInsensitiveSearch];
    }];
    
    NSMutableArray *arrayResult = [NSMutableArray arrayWithCapacity:1];
    for (int i = indexFrom;i < indexFrom + count &&  i < [array count]; i++) {
        [arrayResult addObject:[array objectAtIndex:i]];
    }
    return arrayResult;
}

+ (NSMutableArray *) listUserLiasonAndContactByUser:(NSString*)_userId from:(int)indexFrom numberPage:(int)count {
    CBLView* view = [[CouchBaseLiteLib sharedCouchBaseLite].database viewNamed: @"listsNewContact"];
    if (!view.mapBlock) {
        // Register the map function, the first time we access the view:
        [view setMapBlock: MAPBLOCK({
            if (([doc[@"Table"] isEqualToString:kLiaisonDocType] && doc[@"personInCharge"] && ![doc[@"personInCharge"] isEqualToString:@""])|| ([doc[@"Table"] isEqualToString:kUserDocType] && [[doc objectForKey:@"status"] intValue] == 1))
                emit(doc, nil);
        }) reduceBlock: nil version: @"1.0"]; // bump version any time you change the MAPBLOCK body!
    }
    CBLQuery *query = [view query];
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:1];
    for (CBLQueryRow *row in query.rows) {
        //Contractor chọn được nó + những user thuộc Contact Mgmt ma` no' Add
        if ([[row.document propertyForKey:@"Table"] isEqualToString:kUserDocType]) {
            NSString *userId = [row.document propertyForKey:@"_id"];
            if ([userId isEqualToString:_userId])
                [array addObject:[row.document.properties mutableCopy]];
        }
        else {
            //những user thuộc Contact Mgmt ma` no' Add
            NSString *userId = [row.document propertyForKey:@"userId"];
            NSString *role   = [[row.document propertyForKey:@"typeLiaison"] lowercaseString];
            if ([userId isEqualToString:_userId] && ![role isEqualToString:@"admin"])
                [array addObject:[row.document.properties mutableCopy]];
        }
    }
    [array sortUsingComparator:^(NSMutableDictionary *obj1, NSMutableDictionary *obj2){
        NSString *name1;
        if ([[obj1 objectForKey:@"Table"] isEqualToString:kUserDocType])
            name1 = [obj1 objectForKey:@"name"];
        else
            name1 = [obj1 objectForKey:@"personInCharge"];
        
        NSString *name2;
        if ([[obj2 objectForKey:@"Table"] isEqualToString:kUserDocType])
            name2 = [obj2 objectForKey:@"name"];
        else
            name2 = [obj2 objectForKey:@"personInCharge"];
        
        return [name1 compare:name2 options:NSCaseInsensitiveSearch];
    }];
    
    NSMutableArray *arrayResult = [NSMutableArray arrayWithCapacity:1];
    for (int i = indexFrom;i < indexFrom + count &&  i < [array count]; i++) {
        [arrayResult addObject:[array objectAtIndex:i]];
    }
    return arrayResult;
}

@end
